From: Lucas Stach <l.stach@pengutronix.de>
To: Michael Turquette <mturquette@baylibre.com>,
Stephen Boyd <sboyd@kernel.org>, Rob Herring <robh+dt@kernel.org>,
Shawn Guo <shawnguo@kernel.org>
Cc: Fabio Estevam <fabio.estevam@nxp.com>,
kernel@pengutronix.de, linux-imx@nxp.com,
linux-clk@vger.kernel.org, devicetree@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
patchwork-lst@pengutronix.de
Subject: [PATCH 3/3] clk: imx6q: handle ENET PLL bypass
Date: Tue, 31 Jul 2018 12:20:09 +0200 [thread overview]
Message-ID: <20180731102009.6710-3-l.stach@pengutronix.de> (raw)
In-Reply-To: <20180731102009.6710-1-l.stach@pengutronix.de>
The ENET PLL is different from the other i.MX6 PLLs, as it has
multiple outputs with different post-dividers, which are all
bypassed if the single bypass bit is activated. The hardware setup
looks something like this:
_
refclk-o---PLL---o----DIV1-----| \
| | |M |----OUT1
o-----------------------|_/
| | _
| o----DIV2-----| \
| | |M |----OUT2
o-----------------------|_/
| | _
| `----DIV3-----| \
| |M |----OUT3
`-----------------------|_/
The bypass bit not only bypasses the PLL, but also the attached
post-dividers. This would be reasonbly straight forward to model
with a single output, or with different bypass bits for each output,
but sadly the HW guys decided that it would be good to actuate all
3 muxes with a single bit.
So the need to have the PLL bypassed for one of the outputs always
affects 2 other (in our model) independent branches of the clock
tree.
This means the decision to bypass this PLL is a system wide design
choice and should not be changed on-the-fly, so we can treat any
bapass configuration as static. As such we can just register the
post-dividiers with a ratio that reflects the bypass status, which
allows us to bypass the PLL without breaking our abstraction model
and with it DT stability.
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
drivers/clk/imx/clk-imx6q.c | 63 +++++++++++++++++++++++++++++++++----
1 file changed, 57 insertions(+), 6 deletions(-)
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index f64f0fe76658..c52294694273 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -231,6 +231,41 @@ static void of_assigned_ldb_sels(struct device_node *node,
}
}
+static bool pll6_bypassed(struct device_node *node)
+{
+ int index, ret, num_clocks;
+ struct of_phandle_args clkspec;
+
+ num_clocks = of_count_phandle_with_args(node, "assigned-clocks",
+ "#clock-cells");
+ if (num_clocks < 0)
+ return false;
+
+ for (index = 0; index < num_clocks; index++) {
+ ret = of_parse_phandle_with_args(node, "assigned-clocks",
+ "#clock-cells", index,
+ &clkspec);
+ if (ret < 0)
+ return false;
+
+ if (clkspec.np == node &&
+ clkspec.args[0] == IMX6QDL_PLL6_BYPASS)
+ break;
+ }
+
+ /* PLL6 bypass is not part of the assigned clock list */
+ if (index == num_clocks)
+ return false;
+
+ ret = of_parse_phandle_with_args(node, "assigned-clock-parents",
+ "#clock-cells", index, &clkspec);
+
+ if (clkspec.args[0] != IMX6QDL_CLK_PLL6)
+ return true;
+
+ return false;
+}
+
#define CCM_CCDR 0x04
#define CCM_CCSR 0x0c
#define CCM_CS2CDR 0x2c
@@ -510,16 +545,32 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
clk[IMX6QDL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
- clk[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 5);
- clk[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 4);
+ /*
+ * The ENET PLL is special in that is has multiple outputs with
+ * different post-dividers that are all affected by the single bypass
+ * bit, so a single mux bit affects 3 independent branches of the clock
+ * tree. There is no good way to model this in the clock framework and
+ * dynamically changing the bypass bit, will yield unexpected results.
+ * So we treat any configuration that bypasses the ENET PLL as
+ * essentially static with the divider ratios refelcting the bypass
+ * status.
+ *
+ */
+ if (!pll6_bypassed(ccm_node)) {
+ clk[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 5);
+ clk[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 4);
+ clk[IMX6QDL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
+ base + 0xe0, 0, 2, 0, clk_enet_ref_table,
+ &imx_ccm_lock);
+ } else {
+ clk[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 1);
+ clk[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 1);
+ clk[IMX6QDL_CLK_ENET_REF] = imx_clk_fixed_factor("enet_ref", "pll6_enet", 1, 1);
+ }
clk[IMX6QDL_CLK_SATA_REF_100M] = imx_clk_gate("sata_ref_100m", "sata_ref", base + 0xe0, 20);
clk[IMX6QDL_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
- clk[IMX6QDL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
- base + 0xe0, 0, 2, 0, clk_enet_ref_table,
- &imx_ccm_lock);
-
clk[IMX6QDL_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
clk[IMX6QDL_CLK_LVDS2_SEL] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
--
2.18.0
next prev parent reply other threads:[~2018-07-31 10:20 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-07-31 10:20 [PATCH 1/3] clk: imx6q: reset exclusive gates on init Lucas Stach
2018-07-31 10:20 ` [PATCH 2/3] clk: imx6q: optionally get CCM inputs via standard clock handles Lucas Stach
2018-08-14 16:08 ` Rob Herring
2018-08-21 8:56 ` A.s. Dong
2018-10-15 17:01 ` Stephen Boyd
2018-07-31 10:20 ` Lucas Stach [this message]
2018-08-10 7:45 ` [PATCH 3/3] clk: imx6q: handle ENET PLL bypass Stefan Agner
2018-08-23 12:42 ` Lucas Stach
2018-08-21 8:01 ` [PATCH 1/3] clk: imx6q: reset exclusive gates on init A.s. Dong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180731102009.6710-3-l.stach@pengutronix.de \
--to=l.stach@pengutronix.de \
--cc=devicetree@vger.kernel.org \
--cc=fabio.estevam@nxp.com \
--cc=kernel@pengutronix.de \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-clk@vger.kernel.org \
--cc=linux-imx@nxp.com \
--cc=mturquette@baylibre.com \
--cc=patchwork-lst@pengutronix.de \
--cc=robh+dt@kernel.org \
--cc=sboyd@kernel.org \
--cc=shawnguo@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).