summaryrefslogtreecommitdiff
path: root/drivers/clk/imx
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/imx')
-rw-r--r--drivers/clk/imx/Makefile2
-rw-r--r--drivers/clk/imx/clk-gate-93.c146
-rw-r--r--drivers/clk/imx/clk-imx93.c4
-rw-r--r--drivers/clk/imx/clk.h3
4 files changed, 152 insertions, 3 deletions
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index 2e44b249cb..4eebc34092 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -20,4 +20,4 @@ obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MP) += clk-imx8mp.o clk-pll14xx.o \
obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1020) += clk-imxrt1020.o
obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1050) += clk-imxrt1050.o
-obj-$(CONFIG_$(SPL_TPL_)CLK_IMX93) += clk-imx93.o clk-fracn-gppll.o
+obj-$(CONFIG_$(SPL_TPL_)CLK_IMX93) += clk-imx93.o clk-fracn-gppll.o clk-gate-93.o
diff --git a/drivers/clk/imx/clk-gate-93.c b/drivers/clk/imx/clk-gate-93.c
new file mode 100644
index 0000000000..7b43f18e6e
--- /dev/null
+++ b/drivers/clk/imx/clk-gate-93.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2022 NXP
+ *
+ * Author: Alice Guo <alice.guo@nxp.com>
+ */
+
+#include <asm/io.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/bug.h>
+#include <linux/clk-provider.h>
+
+#include "clk.h"
+
+#define LPCG_DIRECT 0x0
+#define LPCG_LPM_CUR 0x1c
+#define LPM_SETTING_OFF 0x0
+#define LPM_SETTING_ON 0x4
+#define LPCG_AUTHEN 0x30
+#define WHITE_LIST_DM0 16
+#define DOMAIN_ID_A55 3
+#define TZ_NS BIT(9)
+#define CPULPM_MOD BIT(2)
+
+struct imx93_clk_gate {
+ struct clk clk;
+ void __iomem *reg_base;
+ u8 lpcg_on_offset;
+ u8 lpcg_on_ctrl;
+ u8 lpcg_on_mask;
+ ulong flags;
+};
+
+#define to_imx93_clk_gate(_clk) container_of(_clk, struct imx93_clk_gate, clk)
+
+static bool imx93_clk_gate_check_authen(void __iomem *reg_base)
+{
+ u32 authen;
+
+ authen = readl(reg_base + LPCG_AUTHEN);
+ if (!(authen & TZ_NS) || !(authen & BIT(WHITE_LIST_DM0 + DOMAIN_ID_A55)))
+ return false;
+
+ return true;
+}
+
+static void imx93_clk_gate_ctrl_hw(struct clk *clk, bool enable)
+{
+ struct imx93_clk_gate *gate = to_imx93_clk_gate(clk);
+ u32 v;
+
+ v = readl(gate->reg_base + LPCG_AUTHEN);
+ if (v & CPULPM_MOD) {
+ v = enable ? LPM_SETTING_ON : LPM_SETTING_OFF;
+ writel(v, gate->reg_base + LPCG_LPM_CUR);
+ } else {
+ v = readl(gate->reg_base + LPCG_DIRECT);
+ v &= ~(gate->lpcg_on_mask << gate->lpcg_on_offset);
+ if (enable)
+ v |= (gate->lpcg_on_ctrl & gate->lpcg_on_mask) << gate->lpcg_on_offset;
+ writel(v, gate->reg_base + LPCG_DIRECT);
+ }
+}
+
+static int imx93_clk_gate_enable(struct clk *clk)
+{
+ struct imx93_clk_gate *gate = to_imx93_clk_gate(clk);
+
+ if (!imx93_clk_gate_check_authen(gate->reg_base))
+ return -EINVAL;
+
+ imx93_clk_gate_ctrl_hw(clk, true);
+
+ return 0;
+}
+
+static int imx93_clk_gate_disable(struct clk *clk)
+{
+ struct imx93_clk_gate *gate = to_imx93_clk_gate(clk);
+
+ if (!imx93_clk_gate_check_authen(gate->reg_base))
+ return -EINVAL;
+
+ imx93_clk_gate_ctrl_hw(clk, false);
+
+ return 0;
+}
+
+static ulong imx93_clk_gate_set_rate(struct clk *clk, ulong rate)
+{
+ struct clk *parent = clk_get_parent(clk);
+
+ if (parent)
+ return clk_set_rate(parent, rate);
+
+ return -ENODEV;
+}
+
+static const struct clk_ops imx93_clk_gate_ops = {
+ .set_rate = imx93_clk_gate_set_rate,
+ .enable = imx93_clk_gate_enable,
+ .disable = imx93_clk_gate_disable,
+ .get_rate = clk_generic_get_rate,
+};
+
+static struct clk *register_clk_gate(const char *name, const char *parent_name,
+ void __iomem *reg_base, u8 lpcg_on_offset,
+ u8 lpcg_on_ctrl, u8 lpcg_on_mask, ulong flags)
+{
+ struct imx93_clk_gate *gate;
+ int ret;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ gate->reg_base = reg_base;
+ gate->lpcg_on_offset = lpcg_on_offset;
+ gate->lpcg_on_ctrl = lpcg_on_ctrl;
+ gate->lpcg_on_mask = lpcg_on_mask;
+ gate->flags = flags;
+
+ ret = clk_register(&gate->clk, "imx93_clk_gate", name, parent_name);
+ if (ret) {
+ kfree(gate);
+ return ERR_PTR(ret);
+ }
+
+ return &gate->clk;
+}
+
+struct clk *clk_register_imx93_clk_gate(const char *name, const char *parent_name,
+ void __iomem *reg_base, u8 lpcg_on_offset,
+ ulong flags)
+{
+ return register_clk_gate(name, parent_name, reg_base, lpcg_on_offset, 1,
+ 1, flags | CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+}
+
+U_BOOT_DRIVER(imx93_clk_gate) = {
+ .name = "imx93_clk_gate",
+ .id = UCLASS_CLK,
+ .ops = &imx93_clk_gate_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/imx/clk-imx93.c b/drivers/clk/imx/clk-imx93.c
index 87ba829841..f0d7f49a1f 100644
--- a/drivers/clk/imx/clk-imx93.c
+++ b/drivers/clk/imx/clk-imx93.c
@@ -407,8 +407,8 @@ static int imx93_clk_probe(struct udevice *dev)
for (int i = 0; i < ARRAY_SIZE(clk_ccgrs); i++) {
ccgr = &clk_ccgrs[i];
- clk = imx_clk_gate4_flags(ccgr->name, ccgr->parent_names,
- ccm_base + ccgr->off, 0, ccgr->flags);
+ clk = clk_register_imx93_clk_gate(ccgr->name, ccgr->parent_names,
+ ccm_base + ccgr->off, 0, ccgr->flags);
clk_dm(ccgr->clk_id, clk);
}
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index dd4df82125..e690756150 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -52,6 +52,9 @@ struct imx93_pll_fracn_gp {
struct clk *clk_register_imx93_pll(const char *name, const char *parent_name,
void __iomem *reg);
+struct clk *clk_register_imx93_clk_gate(const char *name, const char *parent_name,
+ void __iomem *reg_base, u8 lpcg_on_offset,
+ ulong flags);
struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
void __iomem *base,