The Alaska® Ultra 88E1111 Gigabit Ethernet Transceiver is a physical layer device for Ethernet 1000BASE-T, 100BASE-TX, and 10BASE-T applications.
1. FEATURES
• 10/100/1000BASE-T IEEE 802.3 compliant
• Supports GMII, TBI, reduced pin count GMII (RGMII), reduced pin count TBI (RTBI), and serial GMII (SGMII) interfaces
• Integrated 1.25 GHz SERDES for 1000BASE-X fiber applications
• Four RGMII timing modes
• Energy Detect and Energy Detect+ low power modes
• Three loopback modes for diagnostics
• "Downshift" mode for two-pair cable installations
• Fully integrated digital adaptive equalizers, echo cancellers, and crosstalk cancellers
• Advanced digital baseline wander correction
• Automatic MDI/MDIX crossover at all speeds of operation
• Automatic polarity correction
• IEEE 802.3u compliant Auto-Negotiation
• Software programmable LED modes including LED testing
• Automatic detection of fiber or copper operation
• Supports IEEE 1149.1 JTAG
• Two-Wire Serial Interface (TWSI) and MDC/MDIO
• CRC checker, packet counter
• Packet generation
• Virtual Cable Tester (VCT)
• Auto-Calibration for MAC Interface outputs
• Requires only two supplies: 2.5V and 1.0V (with 1.2V option for the 1.0V supply)
• I/Os are 3.3V tolerant
• Low power dissipation Pave = 0.75W
• 0.13 μm digital CMOS process
• 117-Pin TFBGA, 96-Pin BCC, and 128 PQFP package options
• 117-Pin TFBGA and 96-Pin BCC packages available in Commercial or Industrial grade
• RoHS 6/6 compliant packages available
2. driver:
-
drivers/net/phy/marvell.c
-
drivers/net/phy/phy_device.c
-
include/uapi/linux/mii.h (register)
3. kernel config:
Device Drivers --->[*] Network device support --->-*- PHY Device support and infrastructure ---><*> Marvell PHYs
4. dts config:
mdio {#address-cells = <1>;#size-cells = <0>;compatible = "snps,dwmac-mdio";phy0: phy@0 {device_tpye = "ethernet-phy";compatible = "ethernet-phy-id0141.0cc0", "ethernet-phy-ieee802.3-c22";reg = <0>;};};
pay attention to reg(phy_addr), it will be used in of_mdiobus_register().
the reg(phy_addr) need to be the same as address in PHY configuration, see 6.1
if there is no reg property in dts, of_mdiobus_register() will auto scan for PHYs with empty reg property.
5. PHY driver
-
first, we need get and register all PHY device into bus.
-
second, register PHY driver by module_phy_driver().
-
third, when we excute "ifconfig eth0 up", kernel will call stmmac_init_phy() to init a PHY.
5.1 register PHY device
bring up all the PHYs on a given bus and attach them to bus(register them)
stmmac_dvr_probe -> stmmac_mdio_register -> of_mdiobus_register -> mdiobus_register -> __mdiobus_register -> mdiobus_scan -> get_phy_device & phy_device_register
for (i = 0; i < PHY_MAX_ADDR; i++) {if ((bus->phy_mask & (1 << i)) == 0) {struct phy_device *phydev;phydev = mdiobus_scan(bus, i);if (IS_ERR(phydev) && (PTR_ERR(phydev) != -ENODEV)) {err = PTR_ERR(phydev);goto error;}}
}struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
{struct phy_device *phydev;int err;phydev = get_phy_device(bus, addr, false);if (IS_ERR(phydev))return phydev;/** For DT, see if the auto-probed phy has a correspoding child* in the bus node, and set the of_node pointer in this case.*/of_mdiobus_link_mdiodev(bus, &phydev->mdio);err = phy_device_register(phydev);if (err) {phy_device_free(phydev);return ERR_PTR(-ENODEV);}return phydev;
}
if get_phy_id() is ok, there is a valid PHY device on given addr(PHY addr, also var i). then we create phy device using this addr.
struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
{struct phy_c45_device_ids c45_ids = {0};u32 phy_id = 0;int r;r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids);if (r)return ERR_PTR(r);/* If the phy_id is mostly Fs, there is no device there */if ((phy_id & 0x1fffffff) == 0x1fffffff)return ERR_PTR(-ENODEV);return phy_device_create(bus, addr, phy_id, is_c45, &c45_ids);
}
5.2 register PHY driver
register PHY driver by module_phy_driver(). PHY device and PHY driver will be matched by phy_id. kernel will excute phy_probe() once match is successful.
module_phy_driver(marvell_drivers) -> phy_module_driver -> phy_module_init -> phy_drivers_register -> phy_driver_register -> driver_register(&new_driver->mdiodrv.driver)
5.3 init PHY(register)
when we excute "ifconfig eth0 up", kernel will call stmmac_init_phy() to init a PHY.
stmmac_open -> stmmac_init_phy -> phy_connect -> bus_find_device_by_name & phy_connect_direct()
snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x",priv->plat->bus_id);snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,priv->plat->phy_addr);phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link,interface);
we can find a specified PHY device(the name is phy_id_fmt which contain phy_addr ) by bus_find_device_by_name().
in __mdiobus_register(), if get a PHY device, it call dev_set_name(&mdiodev->dev, PHY_ID_FMT, bus->id, addr) set device name in phy_device_create.
so we can init a PHY that have been registed in bus.