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

From: Sven Van Asbroeck
Date: Sun Jul 12 2020 - 20:25:30 EST


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@xxxxxxxxx>
---

Tree: v5.8-rc4

To: Shawn Guo <shawnguo@xxxxxxxxxx>
To: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx>
Cc: Pengutronix Kernel Team <kernel@xxxxxxxxxxxxxx>
Cc: Fabio Estevam <festevam@xxxxxxxxx>
Cc: NXP Linux Team <linux-imx@xxxxxxx>
Cc: linux-kernel@xxxxxxxxxxxxxxx
Cc: linux-arm-kernel@xxxxxxxxxxxxxxxxxxx
Cc: linux-clk@xxxxxxxxxxxxxxx

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

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)

--
2.17.1