IMX8QM以太网

imx8qm包含两路RGMII和MDIO接口,在电路中两路RGMII可共享同一路MDIO接口或各自采用独立的MDIO接口实现对PHY的读写和控制。下面根据不同的连接方式来实现内核中dts的配置。

1. 仅使用一路RGMII接口

  • fec1 dts配置
&fec1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_fec1>;
        phy-mode = "rgmii-txid";
        phy-handle = <&ethphy0>;
        fsl,magic-packet;
        nvmem-cells = <&fec_mac0>;
        nvmem-cell-names = "mac-address";
        fsl,rgmii_rxc_dly;
        status = "okay";

        mdio {
                #address-cells = <1>;
                #size-cells = <0>;

                ethphy0: ethernet-phy@0 {
                        compatible = "ethernet-phy-ieee802.3-c22";
                        reg = <0>;
                        at803x,eee-disabled;
                        at803x,vddio-1p8v;
                        qca,clk-out-frequency = <125000000>;
                };
        };
};
&iomuxc {
        pinctrl_fec1: fec1grp {
                fsl,pins = <
                        IMX8QM_COMP_CTL_GPIO_1V8_3V3_ENET_ENETB_PAD             0x000014a0
                        IMX8QM_ENET0_MDC_CONN_ENET0_MDC                         0x06000020
                        IMX8QM_ENET0_MDIO_CONN_ENET0_MDIO                       0x06000020
                        IMX8QM_ENET0_RGMII_TX_CTL_CONN_ENET0_RGMII_TX_CTL       0x06000020
                        IMX8QM_ENET0_RGMII_TXC_CONN_ENET0_RGMII_TXC             0x06000020
                        IMX8QM_ENET0_RGMII_TXD0_CONN_ENET0_RGMII_TXD0           0x06000020
                        IMX8QM_ENET0_RGMII_TXD1_CONN_ENET0_RGMII_TXD1           0x06000020
                        IMX8QM_ENET0_RGMII_TXD2_CONN_ENET0_RGMII_TXD2           0x06000020
                        IMX8QM_ENET0_RGMII_TXD3_CONN_ENET0_RGMII_TXD3           0x06000020
                        IMX8QM_ENET0_RGMII_RXC_CONN_ENET0_RGMII_RXC             0x06000020
                        IMX8QM_ENET0_RGMII_RX_CTL_CONN_ENET0_RGMII_RX_CTL       0x06000020
                        IMX8QM_ENET0_RGMII_RXD0_CONN_ENET0_RGMII_RXD0           0x06000020
                        IMX8QM_ENET0_RGMII_RXD1_CONN_ENET0_RGMII_RXD1           0x06000020
                        IMX8QM_ENET0_RGMII_RXD2_CONN_ENET0_RGMII_RXD2           0x06000020
                        IMX8QM_ENET0_RGMII_RXD3_CONN_ENET0_RGMII_RXD3           0x06000020
                >;
        };
};
  • fec2 dts配置
&fec2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_fec2>;
        phy-mode = "rgmii-txid";
        phy-handle = <&ethphy1>;
        fsl,magic-packet;

        nvmem-cells = <&fec_mac1>;
        nvmem-cell-names = "mac-address";
        fsl,rgmii_rxc_dly;
        status = "okay";
        mdio {
                #address-cells = <1>;
                #size-cells = <0>;

                ethphy1: ethernet-phy@1 {
                        compatible = "ethernet-phy-ieee802.3-c22";
                        reg = <1>;
                        at803x,eee-disabled;
                        at803x,vddio-1p8v;
                        qca,clk-out-frequency = <125000000>;
                };
        };
};
&iomuxc {
        pinctrl_fec2: fec2grp {
                fsl,pins = <
                        IMX8QM_COMP_CTL_GPIO_1V8_3V3_ENET_ENETA_PAD             0x000014a0
                        IMX8QM_ENET1_MDC_CONN_ENET1_MDC                         0x06000020
                        IMX8QM_ENET1_MDIO_CONN_ENET1_MDIO                       0x06000020
                        IMX8QM_ENET1_RGMII_TX_CTL_CONN_ENET1_RGMII_TX_CTL       0x00000060
                        IMX8QM_ENET1_RGMII_TXC_CONN_ENET1_RGMII_TXC             0x00000060
                        IMX8QM_ENET1_RGMII_TXD0_CONN_ENET1_RGMII_TXD0           0x00000060
                        IMX8QM_ENET1_RGMII_TXD1_CONN_ENET1_RGMII_TXD1           0x00000060
                        IMX8QM_ENET1_RGMII_TXD2_CONN_ENET1_RGMII_TXD2           0x00000060
                        IMX8QM_ENET1_RGMII_TXD3_CONN_ENET1_RGMII_TXD3           0x00000060
                        IMX8QM_ENET1_RGMII_RXC_CONN_ENET1_RGMII_RXC             0x00000060
                        IMX8QM_ENET1_RGMII_RX_CTL_CONN_ENET1_RGMII_RX_CTL       0x00000060
                        IMX8QM_ENET1_RGMII_RXD0_CONN_ENET1_RGMII_RXD0           0x00000060
                        IMX8QM_ENET1_RGMII_RXD1_CONN_ENET1_RGMII_RXD1           0x00000060
                        IMX8QM_ENET1_RGMII_RXD2_CONN_ENET1_RGMII_RXD2           0x00000060
                        IMX8QM_ENET1_RGMII_RXD3_CONN_ENET1_RGMII_RXD3           0x00000060
                >;
        }; 
};

注意:在只使用一路以太网时请将另一路的网口的“status”属性设置为“disabled”。

2. 公用一路MDIO接口

参考“1”中方式进行如下修改:

&fec1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_fec1>;
        phy-mode = "rgmii-txid";
        phy-handle = <&ethphy0>;
        fsl,magic-packet;
        nvmem-cells = <&fec_mac0>;
        nvmem-cell-names = "mac-address";
        fsl,rgmii_rxc_dly;
        status = "okay";

        mdio {
                #address-cells = <1>;
                #size-cells = <0>;

                ethphy0: ethernet-phy@0 {
                        compatible = "ethernet-phy-ieee802.3-c22";
                        reg = <0>;
                        at803x,eee-disabled;
                        at803x,vddio-1p8v;
                        qca,clk-out-frequency = <125000000>;
                };
                ethphy1: ethernet-phy@1 {
                        compatible = "ethernet-phy-ieee802.3-c22";
                        reg = <1>;
                        at803x,eee-disabled;
                        at803x,vddio-1p8v;
                        qca,clk-out-frequency = <125000000>;
                };                
        };
};
&fec2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_fec2>;
        phy-mode = "rgmii-txid";
        phy-handle = <&ethphy1>;
        fsl,magic-packet;

        nvmem-cells = <&fec_mac1>;
        nvmem-cell-names = "mac-address";
        fsl,rgmii_rxc_dly;
        status = "okay";
};

另外在pinctrl的配置中注释掉不用的 MDIO接口,将需要用的 MDIO接口配置在pinctrl_fec1中。

3. 单独用各自的MDIO接口

这种情况下的配置和“1”中的相同,将两个网口都使能。关于为啥需要在两个网口的节点中分别定义各自的“mdio”节点,这个可以参考驱动(drivers/net/ethernet/freescale/fec_main.c)中fec_enet_mii_init函数。

//下面是部分代码
static int fec_enet_mii_init(struct platform_device *pdev)
{
        static struct mii_bus *fec0_mii_bus;
        static bool *fec_mii_bus_share;
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct fec_enet_private *fep = netdev_priv(ndev);
        bool suppress_preamble = false;
        struct device_node *node;
        int err = -ENXIO;
        u32 mii_speed, holdtime;
        u32 bus_freq;

        /*
         * The i.MX28 dual fec interfaces are not equal.
         * Here are the differences:
         *
         *  - fec0 supports MII & RMII modes while fec1 only supports RMII
         *  - fec0 acts as the 1588 time master while fec1 is slave
         *  - external phys can only be configured by fec0
         *
         * That is to say fec1 can not work independently. It only works
         * when fec0 is working. The reason behind this design is that the
         * second interface is added primarily for Switch mode.
         *
         * Because of the last point above, both phys are attached on fec0
         * mdio interface in board design, and need to be configured by
         * fec0 mii_bus.
         */
        if ((fep->quirks & FEC_QUIRK_SINGLE_MDIO) && fep->dev_id > 0) {
                /* fec1 uses fec0 mii_bus */
                if (mii_cnt && fec0_mii_bus) {
                        fep->mii_bus = fec0_mii_bus;
                        *fec_mii_bus_share = true;
                        mii_cnt++;
                        return 0;
                }
                return -ENOENT;
        }   
        ......
        bus_freq = 2500000; /* 2.5MHz by default */
        node = of_get_child_by_name(pdev->dev.of_node, "mdio");
        if (node) {
                of_property_read_u32(node, "clock-frequency", &bus_freq);
                suppress_preamble = of_property_read_bool(node,
                                                          "suppress-preamble");
        }
        ......
        fep->mii_bus->name = "fec_enet_mii_bus";
        fep->mii_bus->read = fec_enet_mdio_read;
        fep->mii_bus->write = fec_enet_mdio_write;
        snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
                pdev->name, fep->dev_id + 1);
        fep->mii_bus->priv = fep;
        fep->mii_bus->parent = &pdev->dev;

        err = of_mdiobus_register(fep->mii_bus, node);
        if (err)
                goto err_out_free_mdiobus;
        ......
}

上面代码可以看出,通过fec下的mdio子节点来获取一个device_node,of_mdiobus_register注册mdiobus时会将这个device_node传入。
仿照上面的修改后,如果系统启动时在打开eth1提示“fec 5b05000.ethernet eth1: Unable to connect to phy”。说明fec2上的PHY未被识别到。在fec_enet_mii_init函数中添加测试点会发现,这个函数被调用了两次,但是“of_mdiobus_register(fep->mii_bus, node);”注册mdiobus却只被调用了一次。按照DTS中的配置,因为我们在每路网口下都配置mdio节点,所以这里应该是需要调用两次“of_mdiobus_register(fep->mii_bus, node);”来注册各自的mdiobus的。在函数内的第一个“if ((fep->quirks & FEC_QUIRK_SINGLE_MDIO) && fep->dev_id > 0)”前后添加测试log,会发现在fec_enet_mii_init被第二次调用的时候,在这个if中函数返回了。返回的原因if语句前的注释也进行了说明。所以现在需要让函数继续执行,而不是在这里返回,解决的思路就是fep->quirks中取消FEC_QUIRK_SINGLE_MDIO的设置。在“fec_probe”函数中能找到关于这个的设置,并且刚好得调用fec_enet_mii_init函数之前。

static int
fec_probe(struct platform_device *pdev)
{
    ......
        /* board only enable one mii bus in default */
        if (!of_get_property(np, "fsl,mii-exclusive", NULL))
                fep->quirks |= FEC_QUIRK_SINGLE_MDIO;
        ret = fec_enet_mii_init(pdev);
        if (ret)
                goto failed_mii_init;
    ......
}

从代码可以看出只要在dts中添加“fsl,mii-exclusive”属性会跳过FEC_QUIRK_SINGLE_MDIO的设置。如下:

&fec2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_fec2>;
        phy-mode = "rgmii-txid";
        phy-handle = <&ethphy1>;
        fsl,magic-packet;
        fsl,mii-exclusive;
        ......
};

重新编译烧写验证可以发现eth1正常。

你可能感兴趣的:(linux,c语言)