Marvell 88E1111 linux driver

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

 

Marvell 88E1111 linux driver_第1张图片

 

 

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.

你可能感兴趣的:(Linux,Driver,Network,网卡,kernel)