]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
imx8mp: power-domain: Expose high performance PLL clock
authorSumit Garg <sumit.garg@linaro.org>
Thu, 21 Mar 2024 14:55:01 +0000 (20:25 +0530)
committerFabio Estevam <festevam@gmail.com>
Sun, 24 Mar 2024 16:35:59 +0000 (13:35 -0300)
Expose the high performance PLL as clock framework 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. Use last Linux kernel driver
reference commit 7476ddfd36ac ("pmdomain: imx8mp-blk-ctrl: Convert to
platform remove callback returning void").

Tested-by: Tim Harvey <tharvey@gateworks.com> #imx8mp-venice*
Tested-by: Adam Ford <aford173@gmail.com> #imx8mp-beacon-kit
Reviewed-by: Marek Vasut <marex@denx.de>
Signed-off-by: Sumit Garg <sumit.garg@linaro.org>
drivers/power/domain/imx8mp-hsiomix.c

index d3b0c1146cec2ace0e76c434580382e302ceaba6..6188a04c45ed5a907268f1d1f00fbb0d34cedd54 100644 (file)
@@ -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>
 #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;
@@ -123,6 +138,67 @@ 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 as 100 MHz output clock */
+       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 | 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);
@@ -193,6 +269,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,
 };