[PATCH v2 4/8] imx8mp: power-domain: Expose high performance PLL clock

Sumit Garg sumit.garg at linaro.org
Mon Feb 26 09:04:29 CET 2024


Expose the high performance PLL as a regular Linux clock, so the
PCIe PHY can use it when there is no external refclock provided.

Inspired from counterpart Linux kernel v6.8-rc3 driver:
drivers/pmdomain/imx/imx8mp-blk-ctrl.c

Signed-off-by: Sumit Garg <sumit.garg at linaro.org>
---
 drivers/power/domain/imx8mp-hsiomix.c | 78 +++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/drivers/power/domain/imx8mp-hsiomix.c b/drivers/power/domain/imx8mp-hsiomix.c
index 58cc3f63bb56..3e514a603578 100644
--- a/drivers/power/domain/imx8mp-hsiomix.c
+++ b/drivers/power/domain/imx8mp-hsiomix.c
@@ -6,9 +6,15 @@
 #include <common.h>
 #include <asm/io.h>
 #include <clk.h>
+#include <clk-uclass.h>
 #include <dm.h>
 #include <dm/device.h>
 #include <dm/device_compat.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
 #include <power-domain-uclass.h>
 
 #include <dt-bindings/power/imx8mp-power.h>
@@ -18,6 +24,15 @@
 #define  USB_CLOCK_MODULE_EN	BIT(1)
 #define  PCIE_PHY_APB_RST	BIT(4)
 #define  PCIE_PHY_INIT_RST	BIT(5)
+#define GPR_REG1		0x4
+#define  PLL_LOCK		BIT(13)
+#define GPR_REG2		0x8
+#define  P_PLL_MASK		GENMASK(5, 0)
+#define  M_PLL_MASK		GENMASK(15, 6)
+#define  S_PLL_MASK		GENMASK(18, 16)
+#define GPR_REG3		0xc
+#define  PLL_CKE		BIT(17)
+#define  PLL_RST		BIT(31)
 
 struct imx8mp_hsiomix_priv {
 	void __iomem *base;
@@ -137,6 +152,68 @@ static int imx8mp_hsiomix_of_xlate(struct power_domain *power_domain,
 	return 0;
 }
 
+static int hsio_pll_clk_enable(struct clk *clk)
+{
+	void *base = (void *)dev_get_driver_data(clk->dev);
+	u32 val;
+	int ret;
+
+	/* Setup HSIO PLL */
+	clrsetbits_le32(base + GPR_REG2,
+			P_PLL_MASK | M_PLL_MASK | S_PLL_MASK,
+			FIELD_PREP(P_PLL_MASK, 12) |
+			FIELD_PREP(M_PLL_MASK, 800) |
+			FIELD_PREP(S_PLL_MASK, 4));
+
+	/* de-assert PLL reset */
+	setbits_le32(base + GPR_REG3, PLL_RST);
+
+	/* enable PLL */
+	setbits_le32(base + GPR_REG3, PLL_CKE);
+
+	/* Check if PLL is locked */
+	ret = readl_poll_sleep_timeout(base + GPR_REG1, val,
+				       val & PLL_LOCK, 10, 100000);
+	if (ret)
+		dev_err(clk->dev, "failed to lock HSIO PLL\n");
+
+	return ret;
+}
+
+static int hsio_pll_clk_disable(struct clk *clk)
+{
+	void *base = (void *)dev_get_driver_data(clk->dev);
+
+	clrbits_le32(base + GPR_REG3, PLL_CKE);
+	clrbits_le32(base + GPR_REG3, PLL_RST);
+
+	return 0;
+}
+
+static const struct clk_ops hsio_pll_clk_ops = {
+	.enable = hsio_pll_clk_enable,
+	.disable = hsio_pll_clk_disable,
+};
+
+U_BOOT_DRIVER(hsio_pll) = {
+	.name = "hsio-pll",
+	.id = UCLASS_CLK,
+	.ops = &hsio_pll_clk_ops,
+};
+
+int imx8mp_hsiomix_bind(struct udevice *dev)
+{
+	struct driver *drv;
+
+	drv = lists_driver_lookup_name("hsio-pll");
+	if (!drv)
+		return -ENOENT;
+
+	return device_bind_with_driver_data(dev, drv, "hsio-pll",
+					    (ulong)dev_read_addr_ptr(dev),
+					    dev_ofnode(dev), NULL);
+}
+
 static int imx8mp_hsiomix_probe(struct udevice *dev)
 {
 	struct imx8mp_hsiomix_priv *priv = dev_get_priv(dev);
@@ -207,6 +284,7 @@ U_BOOT_DRIVER(imx8mp_hsiomix) = {
 	.id		= UCLASS_POWER_DOMAIN,
 	.of_match	= imx8mp_hsiomix_ids,
 	.probe		= imx8mp_hsiomix_probe,
+	.bind		= imx8mp_hsiomix_bind,
 	.priv_auto	= sizeof(struct imx8mp_hsiomix_priv),
 	.ops		= &imx8mp_hsiomix_ops,
 };
-- 
2.34.1



More information about the U-Boot mailing list