net: fec: add MAC internal delayed clock feature support
authorFugang Duan <fugang.duan@nxp.com>
Wed, 28 Jul 2021 11:52:01 +0000 (19:52 +0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 28 Jul 2021 12:38:53 +0000 (13:38 +0100)
i.MX8QM ENET IP version support timing specification that MAC
integrate clock delay in RGMII mode, the delayed TXC/RXC as an
alternative option to work well with various PHYs.

Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c

index 0a741bc..ae32591 100644 (file)
@@ -381,6 +381,9 @@ struct bufdesc_ex {
 #define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF)
 #define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
 
+#define FEC_ENET_TXC_DLY       ((uint)0x00010000)
+#define FEC_ENET_RXC_DLY       ((uint)0x00020000)
+
 /* ENET interrupt coalescing macro define */
 #define FEC_ITR_CLK_SEL                (0x1 << 30)
 #define FEC_ITR_EN             (0x1 << 31)
@@ -543,6 +546,7 @@ struct fec_enet_private {
        struct clk *clk_ref;
        struct clk *clk_enet_out;
        struct clk *clk_ptp;
+       struct clk *clk_2x_txclk;
 
        bool ptp_clk_on;
        struct mutex ptp_clk_mutex;
@@ -565,6 +569,8 @@ struct fec_enet_private {
        uint    phy_speed;
        phy_interface_t phy_interface;
        struct device_node *phy_node;
+       bool    rgmii_txc_dly;
+       bool    rgmii_rxc_dly;
        int     link;
        int     full_duplex;
        int     speed;
index f13a9da..40ea318 100644 (file)
@@ -1137,6 +1137,13 @@ fec_restart(struct net_device *ndev)
        if (fep->bufdesc_ex)
                ecntl |= (1 << 4);
 
+       if (fep->quirks & FEC_QUIRK_DELAYED_CLKS_SUPPORT &&
+           fep->rgmii_txc_dly)
+               ecntl |= FEC_ENET_TXC_DLY;
+       if (fep->quirks & FEC_QUIRK_DELAYED_CLKS_SUPPORT &&
+           fep->rgmii_rxc_dly)
+               ecntl |= FEC_ENET_RXC_DLY;
+
 #ifndef CONFIG_M5272
        /* Enable the MIB statistic event counters */
        writel(0 << 31, fep->hwp + FEC_MIB_CTRLSTAT);
@@ -2000,6 +2007,10 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
                if (ret)
                        goto failed_clk_ref;
 
+               ret = clk_prepare_enable(fep->clk_2x_txclk);
+               if (ret)
+                       goto failed_clk_2x_txclk;
+
                fec_enet_phy_reset_after_clk_enable(ndev);
        } else {
                clk_disable_unprepare(fep->clk_enet_out);
@@ -2010,10 +2021,14 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
                        mutex_unlock(&fep->ptp_clk_mutex);
                }
                clk_disable_unprepare(fep->clk_ref);
+               clk_disable_unprepare(fep->clk_2x_txclk);
        }
 
        return 0;
 
+failed_clk_2x_txclk:
+       if (fep->clk_ref)
+               clk_disable_unprepare(fep->clk_ref);
 failed_clk_ref:
        if (fep->clk_ptp) {
                mutex_lock(&fep->ptp_clk_mutex);
@@ -3704,6 +3719,7 @@ fec_probe(struct platform_device *pdev)
        char irq_name[8];
        int irq_cnt;
        struct fec_devinfo *dev_info;
+       u32 rgmii_delay;
 
        fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
 
@@ -3761,6 +3777,12 @@ fec_probe(struct platform_device *pdev)
        if (ret)
                goto failed_stop_mode;
 
+       /* For rgmii internal delay, valid values are 0ps and 2000ps */
+       if (of_property_read_u32(np, "tx-internal-delay-ps", &rgmii_delay))
+               fep->rgmii_txc_dly = true;
+       if (of_property_read_u32(np, "rx-internal-delay-ps", &rgmii_delay))
+               fep->rgmii_rxc_dly = true;
+
        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);
@@ -3812,6 +3834,11 @@ fec_probe(struct platform_device *pdev)
                fep->clk_ref = NULL;
        fep->clk_ref_rate = clk_get_rate(fep->clk_ref);
 
+       /* clk_2x_txclk is optional, depends on board */
+       fep->clk_2x_txclk = devm_clk_get(&pdev->dev, "enet_2x_txclk");
+       if (IS_ERR(fep->clk_2x_txclk))
+               fep->clk_2x_txclk = 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)) {