diff mbox series

[v1,4/5] clk: imx6q: support improved enet clocking on QuadPlus

Message ID 20200713002512.28742-5-TheSven73@gmail.com (mailing list archive)
State New, archived
Headers show
Series imx6qp QuadPlus: support improved enet clocking | expand

Commit Message

Sven Van Asbroeck July 13, 2020, 12:25 a.m. UTC
On the imx6q QuadPlus, hardware designers have improved the enet
clocking:
                          _
	 anaclk3---------| \
	                 |  |              _
	                 |M |--enet_pad-->| \
	                 |  |             |  |
	 enet_ref---o--->|_/              |M |----enet_ptp
	            |                     |  |
	            o---------------------|_/

Where anaclk3 is an external clock fed into the imx6q via
a pad, typically RGMII_TX_CTL or GPIO_16, when these are
configured in mux mode ENET_REF_CLK.

Board designers can now change the clock tree (via the devicetree)
to choose between all three supported enet clocking methods.

See follow-up devicetree patch for details.

Signed-off-by: Sven Van Asbroeck <TheSven73@gmail.com>
---

Tree: v5.8-rc4

To: Shawn Guo <shawnguo@kernel.org>
To: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Pengutronix Kernel Team <kernel@pengutronix.de>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: NXP Linux Team <linux-imx@nxp.com>
Cc: linux-kernel@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-clk@vger.kernel.org

 drivers/clk/imx/clk-imx6q.c                 | 46 +++++++++++++++++++++
 include/linux/mfd/syscon/imx6q-iomuxc-gpr.h |  1 +
 2 files changed, 47 insertions(+)
diff mbox series

Patch

diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index ba33c79158de..0edffa306a28 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -15,6 +15,8 @@ 
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <soc/imx/revision.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 #include <dt-bindings/clock/imx6qdl-clock.h>
 
 #include "clk.h"
@@ -87,6 +89,8 @@  static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", };
 static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
 static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
 static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
+static const char * const enet_pad_sels[] = { "anaclk3", "enet_ref", };
+static const char * const enet_ptp_sels[] = { "enet_pad", "enet_ref", };
 
 static struct clk_hw **hws;
 static struct clk_hw_onecell_data *clk_hw_data;
@@ -436,6 +440,7 @@  static struct clk_hw * __init imx6q_obtain_fixed_clk_hw(struct device_node *np,
 
 static void __init imx6q_clocks_init(struct device_node *ccm_node)
 {
+	struct regmap *gpr;
 	struct device_node *np;
 	void __iomem *anatop_base, *base;
 	int ret;
@@ -464,6 +469,9 @@  static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	WARN_ON(!base);
 	of_node_put(np);
 
+	gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
+	WARN_ON(IS_ERR_OR_NULL(gpr));
+
 	/* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */
 	if (clk_on_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) {
 		post_div_table[1].div = 1;
@@ -959,6 +967,44 @@  static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	/* Audio-related clocks configuration */
 	clk_set_parent(hws[IMX6QDL_CLK_SPDIF_SEL]->clk, hws[IMX6QDL_CLK_PLL3_PFD3_454M]->clk);
 
+	/*
+	 * The QuadPlus has improved enet clocking:
+	 *                  _
+	 * anaclk3---------| \
+	 *                 |  |              _
+	 *                 |M |--enet_pad-->| \
+	 *                 |  |             |  |
+	 * enet_ref---o--->|_/              |M |----enet_ptp
+	 *            |                     |  |
+	 *            o---------------------|_/
+	 *
+	 * On the plus, three options to generate the enet ptp clock:
+	 *
+	 * a) route enet_ref externally from pad to pad (the default):
+	 *    enet_ptp from enet_pad
+	 *    enet_pad from enet_ref
+	 * b) route internally on SoC from enet_ref:
+	 *    enet_ptp from enet_ref
+	 * c) route external clock (from PHY or oscillator) via pad:
+	 *    enet_ptp from enet_pad
+	 *    enet_pad from anaclk3
+	 *    anaclk3 from PHY or oscillator, add devicetree node
+	 */
+	if (clk_on_imx6qp()) {
+		/*
+		 * anaclk3: clock source from external clock via:
+		 * - RGMII_TX_CTL PAD (mux mode ENET_REF_CLK), or
+		 * - GPIO_16      PAD (mux mode ENET_REF_CLK)
+		 */
+		hws[IMX6QDL_CLK_ANACLK3] = imx6q_obtain_fixed_clk_hw(ccm_node, "anaclk3", 0);
+		hws[IMX6QDL_CLK_ENET_PAD] = imx_clk_hw_mux_regmap("enet_pad", gpr, IOMUXC_GPR1, ffs(IMX6Q_GPR1_ENET_CLK_SEL_MASK) - 1,
+								  1, enet_pad_sels, ARRAY_SIZE(enet_pad_sels));
+		hws[IMX6QDL_CLK_ENET_PTP] = imx_clk_hw_mux_regmap("enet_ptp", gpr, IOMUXC_GPR5, ffs(IMX6Q_GPR5_ENET_TXCLK_SEL_MASK) - 1,
+								  1, enet_ptp_sels, ARRAY_SIZE(enet_ptp_sels));
+		clk_set_parent(hws[IMX6QDL_CLK_ENET_PAD]->clk, hws[IMX6QDL_CLK_ENET_REF]->clk);
+		clk_set_parent(hws[IMX6QDL_CLK_ENET_PTP]->clk, hws[IMX6QDL_CLK_ENET_PAD]->clk);
+	}
+
 	/* All existing boards with PCIe use LVDS1 */
 	if (IS_ENABLED(CONFIG_PCI_IMX6))
 		clk_set_parent(hws[IMX6QDL_CLK_LVDS1_SEL]->clk, hws[IMX6QDL_CLK_SATA_REF_100M]->clk);
diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
index d4b5e527a7a3..ac1bb3695933 100644
--- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
+++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
@@ -240,6 +240,7 @@ 
 #define IMX6Q_GPR4_IPU_RD_CACHE_CTL		BIT(0)
 
 #define IMX6Q_GPR5_L2_CLK_STOP			BIT(8)
+#define IMX6Q_GPR5_ENET_TXCLK_SEL_MASK		BIT(9)
 #define IMX6Q_GPR5_SATA_SW_PD			BIT(10)
 #define IMX6Q_GPR5_SATA_SW_RST			BIT(11)