diff mbox series

[V2,net-next,5/7] net: fec: add MAC internal delayed clock feature support

Message ID 20210728115203.16263-6-qiangqing.zhang@nxp.com (mailing list archive)
State Accepted
Commit fc539459e900a891dda5b586d7b5e3fd5db14218
Delegated to: Netdev Maintainers
Headers show
Series net: fec: add support for i.MX8MQ and i.MX8QM | expand

Checks

Context Check Description
netdev/apply success Patch already applied to net-next
netdev/tree_selection success Clearly marked for net-next

Commit Message

Joakim Zhang July 28, 2021, 11:52 a.m. UTC
From: Fugang Duan <fugang.duan@nxp.com>

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>
---
 drivers/net/ethernet/freescale/fec.h      |  6 +++++
 drivers/net/ethernet/freescale/fec_main.c | 27 +++++++++++++++++++++++
 2 files changed, 33 insertions(+)

Comments

Andrew Lunn July 28, 2021, 2:10 p.m. UTC | #1
> +	/* 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;

I don't see any validation of the only supported values are 0ps and
2000ps.

	Andrew
Joakim Zhang July 29, 2021, 2:32 a.m. UTC | #2
> -----Original Message-----
> From: Andrew Lunn <andrew@lunn.ch>
> Sent: 2021年7月28日 22:11
> To: Joakim Zhang <qiangqing.zhang@nxp.com>
> Cc: davem@davemloft.net; kuba@kernel.org; robh+dt@kernel.org;
> shawnguo@kernel.org; s.hauer@pengutronix.de; kernel@pengutronix.de;
> festevam@gmail.com; dl-linux-imx <linux-imx@nxp.com>;
> netdev@vger.kernel.org; devicetree@vger.kernel.org;
> linux-kernel@vger.kernel.org
> Subject: Re: [PATCH V2 net-next 5/7] net: fec: add MAC internal delayed clock
> feature support
> 
> > +	/* 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;
> 
> I don't see any validation of the only supported values are 0ps and 2000ps.

Hi Andrew,

I also take this into account, since I have limited the value to 0 and 2000 in fec dt-bindings.
It will report error when run dtbs_check if value is not invalid. Another reason is that actually
the value is not program to hardware, we only enable RGMII delay or not. If need, I think we
can only add a dev_warn() here, instead of stop the probe process?

Best Regards,
Joakim Zhang
> 	Andrew
diff mbox series

Patch

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 0a741bc440e4..ae3259164395 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -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;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index f13a9da180a2..40ea318d7396 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -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)) {