zoukankan      html  css  js  c++  java
  • 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
    ");
                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
    ", 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
    ", 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
    ");
                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
    ");                                   |
            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
    ");                                                  |
    #if !defined(CONFIG_M5272)                                                               |
            phy_dev->supported |= SUPPORTED_Pause;                                           |
    #endif                                                                                   |
            phy_dev->advertising = phy_dev->supported;                                       |
        }                                                                                    |
        else                                                                                 |
        {                                                                                    |
            printk("PHY_BASIC_FEATURES
    ");                                                  |
            // 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)
    ",   |
                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
    ", 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
    ");
            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
    ");                                |
                                                                                         |
        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();
    }
  • 相关阅读:
    蝴蝶自在——《萍踪侠影》
    学习OpenCV——关于三通道的CvMat的求和问题
    MFC中的OnTimer和SetTimer
    慎重选择博士后(或博士生)导师
    MFC界面的完善
    MFC CSplitterWnd的用法
    断言(ASSERT)的用法
    OpenCV中lib的添加
    【转】数据结构之位图
    【转】关于windows server 2003不能共享问题
  • 原文地址:https://www.cnblogs.com/zengjfgit/p/6709689.html
Copyright © 2011-2022 走看看