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();
}

 

posted on 2017-04-14 16:53  zengjf  阅读(1676)  评论(0编辑  收藏  举报

导航