首页 > 代码库 > I.MX6 PHY fixup 调用流程 hacking

I.MX6 PHY fixup 调用流程 hacking

/********************************************************************************** *                      I.MX6 PHY fixup 调用流程 hacking * 说明: *     跟一下i.MX6中对PHY进行fixup的代码是如何被调用的。 *               *                                          2017-4-14 深圳 龙华民治樟坑村 曾剑锋 *********************************************************************************/static struct platform_driver fec_driver = {  <-----+    .driver    = {                                  |        .name    = DRIVER_NAME,                     |        .owner    = THIS_MODULE,                    |        .pm    = &fec_pm_ops,                       |        .of_match_table = fec_dt_ids,               |    },                                              |    .id_table = fec_devtype,               ---------*-+    .probe    = fec_probe,                          | |    .remove    = fec_drv_remove,                    | |};                                                  | |                                                    | |module_platform_driver(fec_driver);        ---------+ |                                                      |MODULE_ALIAS("platform:"DRIVER_NAME);                 |MODULE_LICENSE("GPL");                                |                                                      |static int                                            |fec_probe(struct platform_device *pdev)    <----------+{    struct fec_enet_private *fep;    struct fec_platform_data *pdata;    struct net_device *ndev;    int i, irq, ret = 0;    struct resource *r;    const struct of_device_id *of_id;    static int dev_id;    struct device_node *np = pdev->dev.of_node, *phy_node;    int num_tx_qs;    int num_rx_qs;    fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);    /* Init network device */    ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private),                  num_tx_qs, num_rx_qs);    if (!ndev)        return -ENOMEM;    SET_NETDEV_DEV(ndev, &pdev->dev);    /* setup board info structure */    fep = netdev_priv(ndev);    of_id = of_match_device(fec_dt_ids, &pdev->dev);    if (of_id)        pdev->id_entry = of_id->data;    fep->quirks = pdev->id_entry->driver_data;    fep->netdev = ndev;    fep->num_rx_queues = num_rx_qs;    fep->num_tx_queues = num_tx_qs;#if !defined(CONFIG_M5272)    /* default enable pause frame auto negotiation */    if (fep->quirks & FEC_QUIRK_HAS_GBIT)        fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;#endif    /* Select default pin state */    pinctrl_pm_select_default_state(&pdev->dev);    r = platform_get_resource(pdev, IORESOURCE_MEM, 0);    fep->hwp = devm_ioremap_resource(&pdev->dev, r);    if (IS_ERR(fep->hwp)) {        ret = PTR_ERR(fep->hwp);        goto failed_ioremap;    }    fep->pdev = pdev;    fep->dev_id = dev_id++;    platform_set_drvdata(pdev, ndev);    fec_enet_of_parse_stop_mode(pdev);    if (of_get_property(np, "fsl,magic-packet", NULL))        fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET;    phy_node = of_parse_phandle(np, "phy-handle", 0);    if (!phy_node && of_phy_is_fixed_link(np)) {        ret = of_phy_register_fixed_link(np);        if (ret < 0) {            dev_err(&pdev->dev,                "broken fixed-link specification\n");            goto failed_phy;        }        phy_node = of_node_get(np);    }    fep->phy_node = phy_node;    ret = of_get_phy_mode(pdev->dev.of_node);    if (ret < 0) {        pdata = dev_get_platdata(&pdev->dev);        if (pdata)            fep->phy_interface = pdata->phy;        else            fep->phy_interface = PHY_INTERFACE_MODE_MII;    } else {        fep->phy_interface = ret;    }    fep->clk_ipg = devm_clk_get(&pdev->dev, "ipg");    if (IS_ERR(fep->clk_ipg)) {        ret = PTR_ERR(fep->clk_ipg);        goto failed_clk;    }    fep->clk_ahb = devm_clk_get(&pdev->dev, "ahb");    if (IS_ERR(fep->clk_ahb)) {        ret = PTR_ERR(fep->clk_ahb);        goto failed_clk;    }    fep->itr_clk_rate = clk_get_rate(fep->clk_ahb);    /* enet_out is optional, depends on board */    fep->clk_enet_out = devm_clk_get(&pdev->dev, "enet_out");    if (IS_ERR(fep->clk_enet_out))        fep->clk_enet_out = NULL;    fep->ptp_clk_on = false;    mutex_init(&fep->ptp_clk_mutex);    /* clk_ref is optional, depends on board */    fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref");    if (IS_ERR(fep->clk_ref))        fep->clk_ref = NULL;    fep->bufdesc_ex = fep->quirks & FEC_QUIRK_HAS_BUFDESC_EX;    fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");    if (IS_ERR(fep->clk_ptp)) {        fep->clk_ptp = NULL;        fep->bufdesc_ex = false;    }    pm_runtime_enable(&pdev->dev);    ret = fec_enet_clk_enable(ndev, true);    if (ret)        goto failed_clk;    fep->reg_phy = devm_regulator_get(&pdev->dev, "phy");    if (!IS_ERR(fep->reg_phy)) {        ret = regulator_enable(fep->reg_phy);        if (ret) {            dev_err(&pdev->dev,                "Failed to enable phy regulator: %d\n", ret);            goto failed_regulator;        }    } else {        fep->reg_phy = NULL;    }    fec_reset_phy(pdev);    if (fep->bufdesc_ex)        fec_ptp_init(pdev);    ret = fec_enet_init(ndev);               ----------------------------+    if (ret)                                                             |        goto failed_init;                                                |                                                                         |    for (i = 0; i < FEC_IRQ_NUM; i++) {                                  |        irq = platform_get_irq(pdev, i);                                 |        if (irq < 0) {                                                   |            if (i)                                                       |                break;                                                   |            ret = irq;                                                   |            goto failed_irq;                                             |        }                                                                |        ret = devm_request_irq(&pdev->dev, irq, fec_enet_interrupt,      |                       0, pdev->name, ndev);                             |        if (ret)                                                         |            goto failed_irq;                                             |                                                                         |        fep->irq[i] = irq;                                               |    }                                                                    |                                                                         |    ret = of_property_read_u32(np, "fsl,wakeup_irq", &irq);              |    if (!ret && irq < FEC_IRQ_NUM)                                       |        fep->wake_irq = fep->irq[irq];                                   |    else                                                                 |        fep->wake_irq = fep->irq[0];                                     |                                                                         |    init_completion(&fep->mdio_done);                                    |    ret = fec_enet_mii_init(pdev);                                       |    if (ret)                                                             |        goto failed_mii_init;                                            |                                                                         |    /* Carrier starts down, phylib will bring it up */                   |    netif_carrier_off(ndev);                                             |    fec_enet_clk_enable(ndev, false);                                    |    pinctrl_pm_select_sleep_state(&pdev->dev);                           |                                                                         |    ret = register_netdev(ndev);                                         |    if (ret)                                                             |        goto failed_register;                                            |                                                                         |    device_init_wakeup(&ndev->dev, fep->wol_flag &                       |               FEC_WOL_HAS_MAGIC_PACKET);                                |                                                                         |    if (fep->bufdesc_ex && fep->ptp_clock)                               |        netdev_info(ndev, "registered PHC device %d\n", fep->dev_id);    |                                                                         |    fep->rx_copybreak = COPYBREAK_DEFAULT;                               |    INIT_WORK(&fep->tx_timeout_work, fec_enet_timeout_work);             |    return 0;                                                            |                                                                         |failed_register:                                                         |    fec_enet_mii_remove(fep);                                            |failed_mii_init:                                                         |failed_irq:                                                              |failed_init:                                                             |    if (fep->reg_phy)                                                    |        regulator_disable(fep->reg_phy);                                 |failed_regulator:                                                        |    fec_enet_clk_enable(ndev, false);                                    |failed_clk:                                                              |failed_phy:                                                              |    of_node_put(phy_node);                                               |failed_ioremap:                                                          |    free_netdev(ndev);                                                   |                                                                         |    return ret;                                                          |}                                                                        |                                                                         | /*                                                                      |  * XXX:  We need to clean up on failure exits here.                     |  *                                                                      |  */                                                                     |static int fec_enet_init(struct net_device *ndev)      <-----------------+{    struct fec_enet_private *fep = netdev_priv(ndev);    struct fec_enet_priv_tx_q *txq;    struct fec_enet_priv_rx_q *rxq;    struct bufdesc *cbd_base;    dma_addr_t bd_dma;    int bd_size;    unsigned int i;#if defined(CONFIG_ARM)    fep->rx_align = 0xf;    fep->tx_align = 0xf;#else    fep->rx_align = 0x3;    fep->tx_align = 0x3;#endif    fec_enet_alloc_queue(ndev);    if (fep->bufdesc_ex)        fep->bufdesc_size = sizeof(struct bufdesc_ex);    else        fep->bufdesc_size = sizeof(struct bufdesc);    bd_size = (fep->total_tx_ring_size + fep->total_rx_ring_size) *            fep->bufdesc_size;    /* Allocate memory for buffer descriptors. */    cbd_base = dma_alloc_coherent(NULL, bd_size, &bd_dma,                      GFP_KERNEL);    if (!cbd_base) {        return -ENOMEM;    }    memset(cbd_base, 0, bd_size);    /* Get the Ethernet address */    fec_get_mac(ndev);    /* make sure MAC we just acquired is programmed into the hw */    fec_set_mac_address(ndev, NULL);    /* Set receive and transmit descriptor base. */    for (i = 0; i < fep->num_rx_queues; i++) {        rxq = fep->rx_queue[i];        rxq->index = i;        rxq->rx_bd_base = (struct bufdesc *)cbd_base;        rxq->bd_dma = bd_dma;        if (fep->bufdesc_ex) {            bd_dma += sizeof(struct bufdesc_ex) * rxq->rx_ring_size;            cbd_base = (struct bufdesc *)                (((struct bufdesc_ex *)cbd_base) + rxq->rx_ring_size);        } else {            bd_dma += sizeof(struct bufdesc) * rxq->rx_ring_size;            cbd_base += rxq->rx_ring_size;        }    }    for (i = 0; i < fep->num_tx_queues; i++) {        txq = fep->tx_queue[i];        txq->index = i;        txq->tx_bd_base = (struct bufdesc *)cbd_base;        txq->bd_dma = bd_dma;        if (fep->bufdesc_ex) {            bd_dma += sizeof(struct bufdesc_ex) * txq->tx_ring_size;            cbd_base = (struct bufdesc *)             (((struct bufdesc_ex *)cbd_base) + txq->tx_ring_size);        } else {            bd_dma += sizeof(struct bufdesc) * txq->tx_ring_size;            cbd_base += txq->tx_ring_size;        }    }    /* The FEC Ethernet specific entries in the device structure */    ndev->watchdog_timeo = TX_TIMEOUT;    ndev->netdev_ops = &fec_netdev_ops;                --------------------+    ndev->ethtool_ops = &fec_enet_ethtool_ops;                             |                                                                           |    writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);                   |    netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, NAPI_POLL_WEIGHT);  |                                                                           |    if (fep->quirks & FEC_QUIRK_HAS_VLAN)                                  |        /* enable hw VLAN support */                                       |        ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;                         |                                                                           |    if (fep->quirks & FEC_QUIRK_HAS_CSUM) {                                |        ndev->gso_max_segs = FEC_MAX_TSO_SEGS;                             |                                                                           |        /* enable hw accelerator */                                        |        ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM             |                | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO);              |        fep->csum_flags |= FLAG_RX_CSUM_ENABLED;                           |    }                                                                      |                                                                           |    if (fep->quirks & FEC_QUIRK_HAS_AVB) {                                 |        fep->tx_align = 0;                                                 |        fep->rx_align = 0x3f;                                              |    }                                                                      |                                                                           |    ndev->hw_features = ndev->features;                                    |                                                                           |    fec_restart(ndev);                                                     |                                                                           |    return 0;                                                              |}                                                                          |                                                                           |static const struct net_device_ops fec_netdev_ops = {          <-----------+    .ndo_open        = fec_enet_open,               ---------+    .ndo_stop        = fec_enet_close,                       |    .ndo_start_xmit        = fec_enet_start_xmit,            |    .ndo_select_queue       = fec_enet_select_queue,         |    .ndo_set_rx_mode    = set_multicast_list,                |    .ndo_change_mtu        = eth_change_mtu,                 |    .ndo_validate_addr    = eth_validate_addr,               |    .ndo_tx_timeout        = fec_timeout,                    |    .ndo_set_mac_address    = fec_set_mac_address,           |    .ndo_do_ioctl        = fec_enet_ioctl,                   |#ifdef CONFIG_NET_POLL_CONTROLLER                            |    .ndo_poll_controller    = fec_poll_controller,           |#endif                                                       |    .ndo_set_features    = fec_set_features,                 |};                                                           |                                                             |static int                                                   |fec_enet_open(struct net_device *ndev)              <--------+{    struct fec_enet_private *fep = netdev_priv(ndev);    const struct platform_device_id *id_entry =                platform_get_device_id(fep->pdev);    int ret;    pinctrl_pm_select_default_state(&fep->pdev->dev);    ret = fec_enet_clk_enable(ndev, true);    if (ret)        return ret;    /* I should reset the ring buffers here, but I don‘t yet know     * a simple way to do that.     */    ret = fec_enet_alloc_buffers(ndev);    if (ret)        goto err_enet_alloc;    /* Init MAC firstly for suspend/resume with megafix off case */    fec_restart(ndev);    /* Probe and connect to PHY when open the interface */    ret = fec_enet_mii_probe(ndev);                          -----+    if (ret)                                                      |        goto err_enet_mii_probe;                                  |                                                                  |    napi_enable(&fep->napi);                                      |    phy_start(fep->phy_dev);                                      |    netif_tx_start_all_queues(ndev);                              |                                                                  |    pm_runtime_get_sync(ndev->dev.parent);                        |    if ((id_entry->driver_data & FEC_QUIRK_BUG_WAITMODE) &&       |        !fec_enet_irq_workaround(fep))                            |        pm_qos_add_request(&ndev->pm_qos_req,                     |                   PM_QOS_CPU_DMA_LATENCY,                        |                   0);                                            |    else                                                          |        pm_qos_add_request(&ndev->pm_qos_req,                     |                   PM_QOS_CPU_DMA_LATENCY,                        |                   PM_QOS_DEFAULT_VALUE);                         |                                                                  |    device_set_wakeup_enable(&ndev->dev, fep->wol_flag &          |                 FEC_WOL_FLAG_ENABLE);                            |    fep->miibus_up_failed = false;                                |                                                                  |    return 0;                                                     |                                                                  |err_enet_mii_probe:                                               |    fec_enet_free_buffers(ndev);                                  |err_enet_alloc:                                                   |    fep->miibus_up_failed = true;                                 |    if (!fep->mii_bus_share)                                      |        pinctrl_pm_select_sleep_state(&fep->pdev->dev);           |    return ret;                                                   |}                                                                 |                                                                  |static int fec_enet_mii_probe(struct net_device *ndev)       <----+{    struct fec_enet_private *fep = netdev_priv(ndev);    struct phy_device *phy_dev = NULL;    char mdio_bus_id[MII_BUS_ID_SIZE];    char phy_name[MII_BUS_ID_SIZE + 3];    int phy_id;    int dev_id = fep->dev_id;    fep->phy_dev = NULL;    if (fep->phy_node) {        phy_dev = of_phy_connect(ndev, fep->phy_node,                     &fec_enet_adjust_link, 0,                     fep->phy_interface);        if (!phy_dev)            return -ENODEV;    } else {        /* check for attached phy */        for (phy_id = 0; (phy_id < PHY_MAX_ADDR); phy_id++) {            if ((fep->mii_bus->phy_mask & (1 << phy_id)))                continue;            if (fep->mii_bus->phy_map[phy_id] == NULL)                continue;            if (fep->mii_bus->phy_map[phy_id]->phy_id == 0)                continue;            if (dev_id--)                continue;            strlcpy(mdio_bus_id, fep->mii_bus->id, MII_BUS_ID_SIZE);            break;        }        if (phy_id >= PHY_MAX_ADDR) {            netdev_info(ndev, "no PHY, assuming direct connection to switch\n");            strlcpy(mdio_bus_id, "fixed-0", MII_BUS_ID_SIZE);            phy_id = 0;        }        snprintf(phy_name, sizeof(phy_name),             PHY_ID_FMT, mdio_bus_id, phy_id);        phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link,      ---------------+                      fep->phy_interface);                                               |    }                                                                                    |                                                                                         |    if (IS_ERR(phy_dev)) {                                                               |        netdev_err(ndev, "could not attach to PHY\n");                                   |        return PTR_ERR(phy_dev);                                                         |    }                                                                                    |                                                                                         |    /* mask with MAC supported features */                                               |    if (fep->quirks & FEC_QUIRK_HAS_GBIT) {                                              |        phy_dev->supported &= PHY_GBIT_FEATURES;                                         |        // phy_dev->supported &= ~SUPPORTED_1000baseT_Half;                              |        phy_dev->supported |= SUPPORTED_Pause;                                           |        // phy_dev->supported |= SUPPORTED_1000baseT_Half;                               |        printk("FEC_QUIRK_HAS_GBIT\n");                                                  |#if !defined(CONFIG_M5272)                                                               |        phy_dev->supported |= SUPPORTED_Pause;                                           |#endif                                                                                   |        phy_dev->advertising = phy_dev->supported;                                       |    }                                                                                    |    else                                                                                 |    {                                                                                    |        printk("PHY_BASIC_FEATURES\n");                                                  |        // phy_dev->supported &= PHY_BASIC_FEATURES;                                     |        phy_dev->advertising = phy_dev->supported & PHY_BASIC_FEATURES;                  |    }                                                                                    |    // phy_dev->advertising = phy_dev->supported;                                        |                                                                                         |    fep->phy_dev = phy_dev;                                                              |    fep->link = 0;                                                                       |    fep->full_duplex = 0;                                                                |                                                                                         |    netdev_info(ndev, "Freescale FEC PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",   |            fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev),                       |            fep->phy_dev->irq);                                                          |                                                                                         |    return 0;                                                                            |}                                                                                        |                                                                                         |struct phy_device *phy_connect(struct net_device *dev, const char *bus_id,      <--------+                   void (*handler)(struct net_device *),                   phy_interface_t interface){    struct phy_device *phydev;    struct device *d;    int rc;    /* Search the list of PHY devices on the mdio bus for the     * PHY with the requested name     */    d = bus_find_device_by_name(&mdio_bus_type, NULL, bus_id);    if (!d) {        pr_err("PHY %s not found\n", bus_id);        return ERR_PTR(-ENODEV);    }    phydev = to_phy_device(d);    rc = phy_connect_direct(dev, phydev, handler, interface);      --------------+    if (rc)                                                                      |        return ERR_PTR(rc);                                                      |                                                                                 |    return phydev;                                                               |}                                                                                |EXPORT_SYMBOL(phy_connect);                                                      |                                                                                 |int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,   <----+               void (*handler)(struct net_device *),               phy_interface_t interface){    int rc;    rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface);    --------+    if (rc)                                                                       |        return rc;                                                                |                                                                                  |    phy_prepare_link(phydev, handler);                                            |    phy_start_machine(phydev);                                                    |    if (phydev->irq > 0)                                                          |        phy_start_interrupts(phydev);                                             |                                                                                  |    return 0;                                                                     |}                                                                                 |EXPORT_SYMBOL(phy_connect_direct);                                                |                                                                                  |int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,  <-------+              u32 flags, phy_interface_t interface){    struct device *d = &phydev->dev;    int err;    /* Assume that if there is no driver, that it doesn‘t     * exist, and we should use the genphy driver.     */    if (NULL == d->driver) {        if (phydev->is_c45)            d->driver = &genphy_driver[GENPHY_DRV_10G].driver;        else            d->driver = &genphy_driver[GENPHY_DRV_1G].driver;        err = d->driver->probe(d);        if (err >= 0)            err = device_bind_driver(d);        if (err)            return err;    }    if (phydev->attached_dev) {        dev_err(&dev->dev, "PHY already attached\n");        return -EBUSY;    }    phydev->attached_dev = dev;    dev->phydev = phydev;    phydev->dev_flags = flags;    phydev->interface = interface;    phydev->state = PHY_READY;    /* Do initial configuration here, now that     * we have certain key parameters     * (dev_flags and interface)     */    err = phy_init_hw(phydev);          --------------------+    if (err)                                                |        phy_detach(phydev);                                 |    else                                                    |        phy_resume(phydev);                                 |                                                            |    return err;                                             |}                                                           |EXPORT_SYMBOL(phy_attach_direct);                           |                                                            |int phy_init_hw(struct phy_device *phydev)     <------------+{    int ret;    if (!phydev->drv || !phydev->drv->config_init)        return 0;    ret = phy_write(phydev, MII_BMCR, BMCR_RESET);    if (ret < 0)        return ret;    ret = phy_poll_reset(phydev);    if (ret < 0)        return ret;    ret = phy_scan_fixups(phydev);             -------------+    if (ret < 0)                                            |        return ret;                                         |                                                            |    return phydev->drv->config_init(phydev);                |}                                                           |EXPORT_SYMBOL(phy_init_hw);                                 |                                                            |/* Runs any matching fixups for this phydev */              |int phy_scan_fixups(struct phy_device *phydev)     <--------+{    struct phy_fixup *fixup;    mutex_lock(&phy_fixup_lock);    list_for_each_entry(fixup, &phy_fixup_list, list) {      ------------------+        if (phy_needs_fixup(phydev, fixup)) {      --------+                   |            int err = fixup->run(phydev);                  |                   |                                                           |                   |            if (err < 0) {                                 |                   |                mutex_unlock(&phy_fixup_lock);             |                   |                return err;                                |                   |            }                                              |                   |        }                                                  |                   |    }                                                      |                   |    mutex_unlock(&phy_fixup_lock);                         |                   |                                                           |                   |    return 0;                                              |                   |}                                                          |                   |EXPORT_SYMBOL(phy_scan_fixups);                            |                   |                    v--------------------------------------+                   |static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup) |{                                                                              |    if (strcmp(fixup->bus_id, dev_name(&phydev->dev)) != 0)                    |        if (strcmp(fixup->bus_id, PHY_ANY_ID) != 0)                            |            return 0;                                                          |                                                                               |    if ((fixup->phy_uid & fixup->phy_uid_mask) !=                              |        (phydev->phy_id & fixup->phy_uid_mask))                                |        if (fixup->phy_uid != PHY_ANY_UID)                                     |            return 0;                                                          |                                                                               |    return 1;                                                                  |}                                                                              |                                                                               |static LIST_HEAD(phy_fixup_list);                            <-----------------+                                                                               |int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask,  ----*-+               int (*run)(struct phy_device *))                                | |{                                                                              | |    struct phy_fixup *fixup = kzalloc(sizeof(*fixup), GFP_KERNEL);             | |                                                                               | |    if (!fixup)                                                                | |        return -ENOMEM;                                                        | |                                                                               | |    strlcpy(fixup->bus_id, bus_id, sizeof(fixup->bus_id));                     | |    fixup->phy_uid = phy_uid;                                                  | |    fixup->phy_uid_mask = phy_uid_mask;                                        | |    fixup->run = run;                                                          | |                                                                               | |    mutex_lock(&phy_fixup_lock);                                               | |    list_add_tail(&fixup->list, &phy_fixup_list);            <-----------------+ |    mutex_unlock(&phy_fixup_lock);                                               |                                                                                 |    return 0;                                                                    |}                                                                                |EXPORT_SYMBOL(phy_register_fixup);                                               |                                                                                 |static void __init imx6q_enet_phy_init(void)                  -------------------*-+{                                                                                | |    if (IS_BUILTIN(CONFIG_PHYLIB)) {                                             | |        phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK,           | |                ksz9021rn_phy_fixup);                                            | |        phy_register_fixup_for_uid(PHY_ID_KSZ9031, MICREL_PHY_ID_MASK,           | |                ksz9031rn_phy_fixup);                                            | |        phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff,      <-------------+ |                ar8031_phy_fixup);                                 --------------+ |        phy_register_fixup_for_uid(PHY_ID_AR8035, 0xffffffef,                    | |                ar8035_phy_fixup);                                               | |    }                                                                            | |}                                                                                | |                                                                                 | |static int ar8031_phy_fixup(struct phy_device *dev)                <-------------+ |{                                                                                  |    u16 val;                                                                       |                                                                                   |    /* Set RGMII IO voltage to 1.8V */                                             |    phy_write(dev, 0x1d, 0x1f);                                                    |    phy_write(dev, 0x1e, 0x8);                                                     |                                                                                   |    /* disable phy AR8031 SmartEEE function. */                                    |    phy_write(dev, 0xd, 0x3);                                                      |    phy_write(dev, 0xe, 0x805d);                                                   |    phy_write(dev, 0xd, 0x4003);                                                   |    val = phy_read(dev, 0xe);                                                      |    val &= ~(0x1 << 8);                                                            |    phy_write(dev, 0xe, val);                                                      |                                                                                   |    /* To enable AR8031 output a 125MHz clk from CLK_25M */                        |    phy_write(dev, 0xd, 0x7);                                                      |    phy_write(dev, 0xe, 0x8016);                                                   |    phy_write(dev, 0xd, 0x4007);                                                   |                                                                                   |    val = phy_read(dev, 0xe);                                                      |    val &= 0xffe3;                                                                 |    val |= 0x18;                                                                   |    phy_write(dev, 0xe, val);                                                      |                                                                                   |    /* introduce tx clock delay */                                                 |    phy_write(dev, 0x1d, 0x5);                                                     |    val = phy_read(dev, 0x1e);                                                     |    val |= 0x0100;                                                                 |    phy_write(dev, 0x1e, val);                                                     |                                                                                   |    return 0;                                                                      |}                                                                                  |                                                                                   |static inline void imx6q_enet_init(void)        -----------------------------------*-+{                                                                                  | |    imx6_enet_mac_init("fsl,imx6q-fec");                                           | |    imx6q_enet_phy_init();                     <-----------------------------------+ |    imx6q_1588_init();                                                               |    if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_2_0)           |        imx6q_enet_clk_sel();                                                        |    imx6q_enet_plt_init();                                                           |}                                                                                    |                                                                                     |static void __init imx6q_init_machine(void)                                          |{                                                                                    |    struct device *parent;                                                           |                                                                                     |    if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_2_0)           |        imx_print_silicon_rev("i.MX6QP", IMX_CHIP_REVISION_1_0);                     |    else                                                                             |        imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q",                |                 imx_get_soc_revision());                                            |                                                                                     |    mxc_arch_reset_init_dt();                                                        |                                                                                     |    parent = imx_soc_device_init();                                                  |    if (parent == NULL)                                                              |        pr_warn("failed to initialize soc device\n");                                |                                                                                     |    of_platform_populate(NULL, of_default_bus_match_table,                           |                    imx6q_auxdata_lookup, parent);                                   |                                                                                     |    imx6q_enet_init();                                   <---------------------------+    imx_anatop_init();    imx6q_csi_mux_init();    cpu_is_imx6q() ?  imx6q_pm_init() : imx6dl_pm_init();    imx6q_mini_pcie_init();}

 

I.MX6 PHY fixup 调用流程 hacking