summaryrefslogtreecommitdiff
path: root/drivers/clk
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/Kconfig1
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/clk.c3
-rw-r--r--drivers/clk/imx/Kconfig7
-rw-r--r--drivers/clk/imx/Makefile8
-rw-r--r--drivers/clk/imx/clk-blk-ctrl.c342
-rw-r--r--drivers/clk/imx/clk-blk-ctrl.h81
-rw-r--r--drivers/clk/imx/clk-composite-7ulp.c88
-rw-r--r--drivers/clk/imx/clk-composite-8m.c21
-rw-r--r--drivers/clk/imx/clk-gate2.c38
-rw-r--r--drivers/clk/imx/clk-imx-acm-utils.c78
-rw-r--r--drivers/clk/imx/clk-imx-acm-utils.h19
-rw-r--r--drivers/clk/imx/clk-imx6q.c103
-rw-r--r--drivers/clk/imx/clk-imx6sl.c10
-rw-r--r--drivers/clk/imx/clk-imx6sll.c4
-rw-r--r--drivers/clk/imx/clk-imx6sx.c166
-rw-r--r--drivers/clk/imx/clk-imx6ul.c6
-rw-r--r--drivers/clk/imx/clk-imx7d.c23
-rw-r--r--drivers/clk/imx/clk-imx7ulp.c20
-rw-r--r--drivers/clk/imx/clk-imx8dxl-acm.c235
-rw-r--r--drivers/clk/imx/clk-imx8dxl-rsrc.c65
-rw-r--r--drivers/clk/imx/clk-imx8mm.c168
-rw-r--r--drivers/clk/imx/clk-imx8mn.c89
-rw-r--r--drivers/clk/imx/clk-imx8mp.c459
-rw-r--r--drivers/clk/imx/clk-imx8mq.c55
-rw-r--r--drivers/clk/imx/clk-imx8qm-acm.c297
-rw-r--r--drivers/clk/imx/clk-imx8qm-rsrc.c3
-rw-r--r--drivers/clk/imx/clk-imx8qxp-acm.c258
-rw-r--r--drivers/clk/imx/clk-imx8qxp-lpcg.c290
-rw-r--r--drivers/clk/imx/clk-imx8qxp-lpcg.h1
-rw-r--r--drivers/clk/imx/clk-imx8qxp-rsrc.c4
-rw-r--r--drivers/clk/imx/clk-imx8qxp.c15
-rw-r--r--drivers/clk/imx/clk-imx8ulp.c577
-rw-r--r--drivers/clk/imx/clk-lpcg-scu.c39
-rw-r--r--drivers/clk/imx/clk-pfd.c49
-rw-r--r--drivers/clk/imx/clk-pfdv2.c23
-rw-r--r--drivers/clk/imx/clk-pll14xx.c37
-rw-r--r--drivers/clk/imx/clk-pllv3.c84
-rw-r--r--drivers/clk/imx/clk-pllv4.c35
-rw-r--r--drivers/clk/imx/clk-scu.c39
-rw-r--r--drivers/clk/imx/clk-scu.h1
-rw-r--r--drivers/clk/imx/clk.c13
-rw-r--r--drivers/clk/imx/clk.h89
-rw-r--r--drivers/clk/s32/Kconfig4
-rw-r--r--drivers/clk/s32/Makefile2
-rw-r--r--drivers/clk/s32/clk-core.c53
-rw-r--r--drivers/clk/s32/clk.h55
-rw-r--r--drivers/clk/s32/s32v234/Makefile1
-rw-r--r--drivers/clk/s32/s32v234/clk-dfs.c236
-rw-r--r--drivers/clk/s32/s32v234/clk-plldig.c240
-rw-r--r--drivers/clk/s32/s32v234/clk.c299
-rw-r--r--drivers/clk/s32/s32v234/clk.h31
-rw-r--r--drivers/clk/s32/s32v234/dfs.h78
-rw-r--r--drivers/clk/s32/s32v234/mc_cgm.h70
-rw-r--r--drivers/clk/s32/s32v234/mc_me.h110
-rw-r--r--drivers/clk/s32/s32v234/pll.h78
-rw-r--r--drivers/clk/s32/s32v234/src.h17
57 files changed, 4751 insertions, 467 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c5b3dc97396a..023cf9191ea9 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -408,6 +408,7 @@ source "drivers/clk/qcom/Kconfig"
source "drivers/clk/ralink/Kconfig"
source "drivers/clk/renesas/Kconfig"
source "drivers/clk/rockchip/Kconfig"
+source "drivers/clk/s32/Kconfig"
source "drivers/clk/samsung/Kconfig"
source "drivers/clk/sifive/Kconfig"
source "drivers/clk/socfpga/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index e42312121e51..b1b31fa576fd 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -103,6 +103,7 @@ obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
obj-y += ralink/
obj-y += renesas/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
+obj-$(CONFIG_ARCH_S32) += s32/
obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
obj-$(CONFIG_CLK_SIFIVE) += sifive/
obj-y += socfpga/
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 5cef73a85901..7f94ad322c34 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2514,7 +2514,8 @@ static int clk_core_set_parent_nolock(struct clk_core *core,
if (!core)
return 0;
- if (core->parent == parent)
+ if ((core->parent == parent) &&
+ !(core->flags & CLK_SET_PARENT_NOCACHE))
return 0;
/* verify ops for multi-parent clks */
diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig
index 47d9ec3abd2f..0d1e3a6ac32a 100644
--- a/drivers/clk/imx/Kconfig
+++ b/drivers/clk/imx/Kconfig
@@ -98,3 +98,10 @@ config CLK_IMX8QXP
select MXC_CLK_SCU
help
Build the driver for IMX8QXP SCU based clocks.
+
+config CLK_IMX8ULP
+ tristate "IMX8ULP CCM Clock Driver"
+ depends on ARCH_MXC || COMPILE_TEST
+ select RESET_CONTROLLER
+ help
+ Build the driver for i.MX8ULP CCM Clock Driver
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index c24a2acbfa56..c4a18876803d 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -23,13 +23,17 @@ obj-$(CONFIG_MXC_CLK) += mxc-clk.o
obj-$(CONFIG_CLK_IMX8MM) += clk-imx8mm.o
obj-$(CONFIG_CLK_IMX8MN) += clk-imx8mn.o
-obj-$(CONFIG_CLK_IMX8MP) += clk-imx8mp.o
+obj-$(CONFIG_CLK_IMX8MP) += clk-imx8mp.o clk-blk-ctrl.o
obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o
obj-$(CONFIG_MXC_CLK_SCU) += clk-imx-scu.o clk-imx-lpcg-scu.o
clk-imx-scu-$(CONFIG_CLK_IMX8QXP) += clk-scu.o clk-imx8qxp.o \
- clk-imx8qxp-rsrc.o clk-imx8qm-rsrc.o
+ clk-imx8qxp-rsrc.o clk-imx8qm-rsrc.o \
+ clk-imx8dxl-rsrc.o
clk-imx-lpcg-scu-$(CONFIG_CLK_IMX8QXP) += clk-lpcg-scu.o clk-imx8qxp-lpcg.o
+obj-$(CONFIG_CLK_IMX8QXP) += clk-imx8qxp-acm.o clk-imx8qm-acm.o clk-imx8dxl-acm.o clk-imx-acm-utils.o
+
+obj-$(CONFIG_CLK_IMX8ULP) += clk-imx8ulp.o
obj-$(CONFIG_CLK_IMX1) += clk-imx1.o
obj-$(CONFIG_CLK_IMX25) += clk-imx25.o
diff --git a/drivers/clk/imx/clk-blk-ctrl.c b/drivers/clk/imx/clk-blk-ctrl.c
new file mode 100644
index 000000000000..e36035b3e733
--- /dev/null
+++ b/drivers/clk/imx/clk-blk-ctrl.c
@@ -0,0 +1,342 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2020 NXP.
+ */
+
+#include <linux/clk.h>
+#include <linux/reset-controller.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include "clk.h"
+#include "clk-blk-ctrl.h"
+
+struct reset_hw {
+ u32 offset;
+ u32 shift;
+ u32 mask;
+ unsigned long asserted;
+};
+
+struct pm_safekeep_info {
+ uint32_t *regs_values;
+ uint32_t *regs_offsets;
+ uint32_t regs_num;
+};
+
+struct imx_blk_ctrl_drvdata {
+ void __iomem *base;
+ struct reset_controller_dev rcdev;
+ struct reset_hw *rst_hws;
+ struct pm_safekeep_info pm_info;
+
+ spinlock_t *lock;
+};
+
+static int imx_blk_ctrl_reset_set(struct reset_controller_dev *rcdev,
+ unsigned long id, bool assert)
+{
+ struct imx_blk_ctrl_drvdata *drvdata = container_of(rcdev,
+ struct imx_blk_ctrl_drvdata, rcdev);
+ unsigned int offset = drvdata->rst_hws[id].offset;
+ unsigned int shift = drvdata->rst_hws[id].shift;
+ unsigned int mask = drvdata->rst_hws[id].mask;
+ void __iomem *reg_addr = drvdata->base + offset;
+ unsigned long flags;
+ u32 reg;
+
+ if (!assert && !test_bit(1, &drvdata->rst_hws[id].asserted))
+ return -ENODEV;
+
+ if (assert && !test_and_set_bit(1, &drvdata->rst_hws[id].asserted))
+ pm_runtime_get_sync(rcdev->dev);
+
+ spin_lock_irqsave(drvdata->lock, flags);
+
+ reg = readl(reg_addr);
+ if (assert)
+ writel(reg & ~(mask << shift), reg_addr);
+ else
+ writel(reg | (mask << shift), reg_addr);
+
+ spin_unlock_irqrestore(drvdata->lock, flags);
+
+ if (!assert && test_and_clear_bit(1, &drvdata->rst_hws[id].asserted))
+ pm_runtime_put_sync(rcdev->dev);
+
+ return 0;
+}
+
+static int imx_blk_ctrl_reset_reset(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ imx_blk_ctrl_reset_set(rcdev, id, true);
+ return imx_blk_ctrl_reset_set(rcdev, id, false);
+}
+
+static int imx_blk_ctrl_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return imx_blk_ctrl_reset_set(rcdev, id, true);
+}
+
+static int imx_blk_ctrl_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return imx_blk_ctrl_reset_set(rcdev, id, false);
+}
+
+static const struct reset_control_ops imx_blk_ctrl_reset_ops = {
+ .reset = imx_blk_ctrl_reset_reset,
+ .assert = imx_blk_ctrl_reset_assert,
+ .deassert = imx_blk_ctrl_reset_deassert,
+};
+
+static int imx_blk_ctrl_register_reset_controller(struct device *dev)
+{
+ struct imx_blk_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
+ const struct imx_blk_ctrl_dev_data *dev_data = of_device_get_match_data(dev);
+ struct reset_hw *hws;
+ int max = dev_data->resets_max;
+ int i;
+
+ drvdata->lock = &imx_ccm_lock;
+
+ drvdata->rcdev.owner = THIS_MODULE;
+ drvdata->rcdev.nr_resets = max;
+ drvdata->rcdev.ops = &imx_blk_ctrl_reset_ops;
+ drvdata->rcdev.of_node = dev->of_node;
+ drvdata->rcdev.dev = dev;
+
+ drvdata->rst_hws = devm_kzalloc(dev, sizeof(struct reset_hw) * max,
+ GFP_KERNEL);
+ hws = drvdata->rst_hws;
+
+ for (i = 0; i < dev_data->hws_num; i++) {
+ struct imx_blk_ctrl_hw *hw = &dev_data->hws[i];
+
+ if (hw->type != BLK_CTRL_RESET)
+ continue;
+
+ hws[hw->id].offset = hw->offset;
+ hws[hw->id].shift = hw->shift;
+ hws[hw->id].mask = hw->mask;
+ }
+
+ return devm_reset_controller_register(dev, &drvdata->rcdev);
+}
+static struct clk_hw *imx_blk_ctrl_register_one_clock(struct device *dev,
+ struct imx_blk_ctrl_hw *hw)
+{
+ struct imx_blk_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
+ void __iomem *base = drvdata->base;
+ struct clk_hw *clk_hw;
+
+ switch (hw->type) {
+ case BLK_CTRL_CLK_MUX:
+ clk_hw = imx_dev_clk_hw_mux_flags(dev, hw->name,
+ base + hw->offset,
+ hw->shift, hw->width,
+ hw->parents,
+ hw->parents_count,
+ hw->flags);
+ break;
+ case BLK_CTRL_CLK_GATE:
+ clk_hw = imx_dev_clk_hw_gate(dev, hw->name, hw->parents,
+ base + hw->offset, hw->shift);
+ break;
+ case BLK_CTRL_CLK_SHARED_GATE:
+ clk_hw = imx_dev_clk_hw_gate_shared(dev, hw->name,
+ hw->parents,
+ base + hw->offset,
+ hw->shift,
+ hw->shared_count);
+ break;
+ case BLK_CTRL_CLK_PLL14XX:
+ clk_hw = imx_dev_clk_hw_pll14xx(dev, hw->name, hw->parents,
+ base + hw->offset, hw->pll_tbl);
+ break;
+ default:
+ clk_hw = NULL;
+ };
+
+ return clk_hw;
+}
+
+static int imx_blk_ctrl_register_clock_controller(struct device *dev)
+{
+ const struct imx_blk_ctrl_dev_data *dev_data = of_device_get_match_data(dev);
+ struct clk_hw_onecell_data *clk_hw_data;
+ struct clk_hw **hws;
+ int i;
+
+ clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws,
+ dev_data->hws_num), GFP_KERNEL);
+ if (WARN_ON(!clk_hw_data))
+ return -ENOMEM;
+
+ clk_hw_data->num = dev_data->clocks_max;
+ hws = clk_hw_data->hws;
+
+ for (i = 0; i < dev_data->hws_num; i++) {
+ struct imx_blk_ctrl_hw *hw = &dev_data->hws[i];
+ struct clk_hw *tmp = imx_blk_ctrl_register_one_clock(dev, hw);
+
+ if (!tmp)
+ continue;
+ hws[hw->id] = tmp;
+ }
+
+ imx_check_clk_hws(hws, dev_data->clocks_max);
+
+ return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
+ clk_hw_data);
+}
+
+static int imx_blk_ctrl_init_runtime_pm_safekeeping(struct device *dev)
+{
+ const struct imx_blk_ctrl_dev_data *dev_data = of_device_get_match_data(dev);
+ struct imx_blk_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
+ struct pm_safekeep_info *pm_info = &drvdata->pm_info;
+ u32 regs_num = dev_data->pm_runtime_saved_regs_num;
+ const u32 *regs_offsets = dev_data->pm_runtime_saved_regs;
+
+ if (!dev_data->pm_runtime_saved_regs_num)
+ return 0;
+
+ pm_info->regs_values = devm_kzalloc(dev,
+ sizeof(u32) * regs_num,
+ GFP_KERNEL);
+ if (WARN_ON(IS_ERR(pm_info->regs_values)))
+ return PTR_ERR(pm_info->regs_values);
+
+ pm_info->regs_offsets = kmemdup(regs_offsets,
+ regs_num * sizeof(u32), GFP_KERNEL);
+ if (WARN_ON(IS_ERR(pm_info->regs_offsets)))
+ return PTR_ERR(pm_info->regs_offsets);
+
+ pm_info->regs_num = regs_num;
+
+ return 0;
+}
+
+static int imx_blk_ctrl_probe(struct platform_device *pdev)
+{
+ struct imx_blk_ctrl_drvdata *drvdata;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (WARN_ON(!drvdata))
+ return -ENOMEM;
+
+ drvdata->base = devm_platform_ioremap_resource(pdev, 0);
+ if (WARN_ON(IS_ERR(drvdata->base)))
+ return PTR_ERR(drvdata->base);
+
+ dev_set_drvdata(dev, drvdata);
+
+ ret = imx_blk_ctrl_init_runtime_pm_safekeeping(dev);
+ if (ret)
+ return ret;
+
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ ret = imx_blk_ctrl_register_clock_controller(dev);
+ if (ret) {
+ pm_runtime_put(dev);
+ return ret;
+ }
+
+ ret = imx_blk_ctrl_register_reset_controller(dev);
+
+ pm_runtime_put(dev);
+
+ return ret;
+}
+
+static void imx_blk_ctrl_read_write(struct device *dev, bool write)
+{
+ struct imx_blk_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
+ struct pm_safekeep_info *pm_info = &drvdata->pm_info;
+ void __iomem *base = drvdata->base;
+ unsigned long flags;
+ int i;
+
+ if (!pm_info->regs_num)
+ return;
+
+ spin_lock_irqsave(drvdata->lock, flags);
+
+ for (i = 0; i < pm_info->regs_num; i++) {
+ u32 offset = pm_info->regs_offsets[i];
+
+ if (write)
+ writel(pm_info->regs_values[i], base + offset);
+ else
+ pm_info->regs_values[i] = readl(base + offset);
+ }
+
+ spin_unlock_irqrestore(drvdata->lock, flags);
+
+}
+
+static int imx_blk_ctrl_runtime_suspend(struct device *dev)
+{
+ imx_blk_ctrl_read_write(dev, false);
+
+ return 0;
+}
+
+static int imx_blk_ctrl_runtime_resume(struct device *dev)
+{
+ imx_blk_ctrl_read_write(dev, true);
+
+ return 0;
+}
+
+static const struct dev_pm_ops imx_blk_ctrl_pm_ops = {
+ SET_RUNTIME_PM_OPS(imx_blk_ctrl_runtime_suspend,
+ imx_blk_ctrl_runtime_resume, NULL)
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
+static const struct of_device_id imx_blk_ctrl_of_match[] = {
+ {
+ .compatible = "fsl,imx8mp-audio-blk-ctrl",
+ .data = &imx8mp_audio_blk_ctrl_dev_data
+ },
+ {
+ .compatible = "fsl,imx8mp-media-blk-ctrl",
+ .data = &imx8mp_media_blk_ctrl_dev_data
+ },
+ {
+ .compatible = "fsl,imx8mp-hdmi-blk-ctrl",
+ .data = &imx8mp_hdmi_blk_ctrl_dev_data
+ },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_blk_ctrl_of_match);
+
+static struct platform_driver imx_blk_ctrl_driver = {
+ .probe = imx_blk_ctrl_probe,
+ .driver = {
+ .name = "imx-blk-ctrl",
+ .of_match_table = of_match_ptr(imx_blk_ctrl_of_match),
+ .pm = &imx_blk_ctrl_pm_ops,
+ },
+};
+module_platform_driver(imx_blk_ctrl_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/imx/clk-blk-ctrl.h b/drivers/clk/imx/clk-blk-ctrl.h
new file mode 100644
index 000000000000..e0574b20b94c
--- /dev/null
+++ b/drivers/clk/imx/clk-blk-ctrl.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __MACH_IMX_CLK_BLK_CTRL_H
+#define __MACH_IMX_CLK_BLK_CTRL_H
+
+enum imx_blk_ctrl_hw_type {
+ BLK_CTRL_CLK_MUX,
+ BLK_CTRL_CLK_GATE,
+ BLK_CTRL_CLK_SHARED_GATE,
+ BLK_CTRL_CLK_PLL14XX,
+ BLK_CTRL_RESET,
+};
+
+struct imx_blk_ctrl_hw {
+ int type;
+ char *name;
+ u32 offset;
+ u32 shift;
+ u32 mask;
+ u32 width;
+ u32 flags;
+ u32 id;
+ void *parents;
+ u32 parents_count;
+ int *shared_count;
+ const struct imx_pll14xx_clk *pll_tbl;
+};
+
+struct imx_blk_ctrl_dev_data {
+ struct imx_blk_ctrl_hw *hws;
+ u32 hws_num;
+
+ u32 clocks_max;
+ u32 resets_max;
+
+ u32 pm_runtime_saved_regs_num;
+ u32 pm_runtime_saved_regs[];
+};
+
+#define IMX_BLK_CTRL(_type, _name, _id, _offset, _shift, _width, _mask, _parents, _parents_count, _flags, sh_count, _pll_tbl) \
+ { \
+ .type = _type, \
+ .name = _name, \
+ .id = _id, \
+ .offset = _offset, \
+ .shift = _shift, \
+ .width = _width, \
+ .mask = _mask, \
+ .parents = _parents, \
+ .parents_count = _parents_count, \
+ .flags = _flags, \
+ .shared_count = sh_count, \
+ .pll_tbl = _pll_tbl, \
+ }
+
+#define IMX_BLK_CTRL_CLK_MUX(_name, _id, _offset, _shift, _width, _parents) \
+ IMX_BLK_CTRL(BLK_CTRL_CLK_MUX, _name, _id, _offset, _shift, _width, 0, _parents, ARRAY_SIZE(_parents), 0, NULL, NULL)
+
+#define IMX_BLK_CTRL_CLK_MUX_FLAGS(_name, _id, _offset, _shift, _width, _parents, _flags) \
+ IMX_BLK_CTRL(BLK_CTRL_CLK_MUX, _name, _id, _offset, _shift, _width, 0, _parents, ARRAY_SIZE(_parents), _flags, NULL, NULL)
+
+#define IMX_BLK_CTRL_CLK_GATE(_name, _id, _offset, _shift, _parents) \
+ IMX_BLK_CTRL(BLK_CTRL_CLK_GATE, _name, _id, _offset, _shift, 1, 0, _parents, 1, 0, NULL, NULL)
+
+#define IMX_BLK_CTRL_CLK_SHARED_GATE(_name, _id, _offset, _shift, _parents, sh_count) \
+ IMX_BLK_CTRL(BLK_CTRL_CLK_SHARED_GATE, _name, _id, _offset, _shift, 1, 0, _parents, 1, 0, sh_count, NULL)
+
+#define IMX_BLK_CTRL_CLK_PLL14XX(_name, _id, _offset, _parents, _pll_tbl) \
+ IMX_BLK_CTRL(BLK_CTRL_CLK_PLL14XX, _name, _id, _offset, 0, 0, 0, _parents, 1, 0, NULL, _pll_tbl)
+
+#define IMX_BLK_CTRL_RESET(_id, _offset, _shift) \
+ IMX_BLK_CTRL(BLK_CTRL_RESET, NULL, _id, _offset, _shift, 0, 1, NULL, 0, 0, NULL, NULL)
+
+#define IMX_BLK_CTRL_RESET_MASK(_id, _offset, _shift, mask) \
+ IMX_BLK_CTRL(BLK_CTRL_RESET, NULL, _id, _offset, _shift, 0, mask, NULL, 0, 0, NULL, NULL)
+
+extern const struct imx_blk_ctrl_dev_data imx8mp_audio_blk_ctrl_dev_data;
+extern const struct imx_blk_ctrl_dev_data imx8mp_media_blk_ctrl_dev_data;
+extern const struct imx_blk_ctrl_dev_data imx8mp_hdmi_blk_ctrl_dev_data;
+
+#endif
+
diff --git a/drivers/clk/imx/clk-composite-7ulp.c b/drivers/clk/imx/clk-composite-7ulp.c
index d85ba78abbb1..4eedd45dbaa8 100644
--- a/drivers/clk/imx/clk-composite-7ulp.c
+++ b/drivers/clk/imx/clk-composite-7ulp.c
@@ -8,6 +8,7 @@
#include <linux/bits.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
+#include <linux/io.h>
#include <linux/slab.h>
#include "../clk-fractional-divider.h"
@@ -23,17 +24,61 @@
#define PCG_PCD_WIDTH 3
#define PCG_PCD_MASK 0x7
-struct clk_hw *imx7ulp_clk_hw_composite(const char *name,
+#define SW_RST BIT(28)
+
+static int pcc_gate_enable(struct clk_hw *hw)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+ unsigned long flags;
+ u32 val;
+ int ret;
+
+ ret = clk_gate_ops.enable(hw);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(gate->lock, flags);
+ /*
+ * release the sw reset for peripherals associated with
+ * with this pcc clock.
+ */
+ val = readl(gate->reg);
+ val |= SW_RST;
+ writel(val, gate->reg);
+
+ spin_unlock_irqrestore(gate->lock, flags);
+
+ return 0;
+}
+
+static void pcc_gate_disable(struct clk_hw *hw)
+{
+ clk_gate_ops.disable(hw);
+}
+
+static int pcc_gate_is_enabled(struct clk_hw *hw)
+{
+ return clk_gate_ops.is_enabled(hw);
+}
+
+static const struct clk_ops pcc_gate_ops = {
+ .enable = pcc_gate_enable,
+ .disable = pcc_gate_disable,
+ .is_enabled = pcc_gate_is_enabled,
+};
+
+static struct clk_hw *imx_ulp_clk_hw_composite(const char *name,
const char * const *parent_names,
int num_parents, bool mux_present,
bool rate_present, bool gate_present,
- void __iomem *reg)
+ void __iomem *reg, bool has_swrst)
{
struct clk_hw *mux_hw = NULL, *fd_hw = NULL, *gate_hw = NULL;
struct clk_fractional_divider *fd = NULL;
struct clk_gate *gate = NULL;
struct clk_mux *mux = NULL;
struct clk_hw *hw;
+ u32 val;
if (mux_present) {
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
@@ -43,6 +88,8 @@ struct clk_hw *imx7ulp_clk_hw_composite(const char *name,
mux->reg = reg;
mux->shift = PCG_PCS_SHIFT;
mux->mask = PCG_PCS_MASK;
+ if (has_swrst)
+ mux->lock = &imx_ccm_lock;
}
if (rate_present) {
@@ -60,6 +107,8 @@ struct clk_hw *imx7ulp_clk_hw_composite(const char *name,
fd->nwidth = PCG_PCD_WIDTH;
fd->nmask = PCG_PCD_MASK;
fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED;
+ if (has_swrst)
+ fd->lock = &imx_ccm_lock;
}
if (gate_present) {
@@ -72,13 +121,27 @@ struct clk_hw *imx7ulp_clk_hw_composite(const char *name,
gate_hw = &gate->hw;
gate->reg = reg;
gate->bit_idx = PCG_CGC_SHIFT;
+ if (has_swrst)
+ gate->lock = &imx_ccm_lock;
+ /*
+ * make sure clock is gated during clock tree initialization,
+ * the HW ONLY allow clock parent/rate changed with clock gated,
+ * during clock tree initialization, clocks could be enabled
+ * by bootloader, so the HW status will mismatch with clock tree
+ * prepare count, then clock core driver will allow parent/rate
+ * change since the prepare count is zero, but HW actually
+ * prevent the parent/rate change due to the clock is enabled.
+ */
+ val = readl_relaxed(reg);
+ val &= ~(1 << PCG_CGC_SHIFT);
+ writel_relaxed(val, reg);
}
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
mux_hw, &clk_mux_ops, fd_hw,
&clk_fractional_divider_ops, gate_hw,
- &clk_gate_ops, CLK_SET_RATE_GATE |
- CLK_SET_PARENT_GATE);
+ has_swrst ? &pcc_gate_ops : &clk_gate_ops, CLK_SET_RATE_GATE |
+ CLK_SET_PARENT_GATE | CLK_SET_RATE_NO_REPARENT);
if (IS_ERR(hw)) {
kfree(mux);
kfree(fd);
@@ -87,3 +150,20 @@ struct clk_hw *imx7ulp_clk_hw_composite(const char *name,
return hw;
}
+
+struct clk_hw *imx7ulp_clk_hw_composite(const char *name, const char * const *parent_names,
+ int num_parents, bool mux_present, bool rate_present,
+ bool gate_present, void __iomem *reg)
+{
+ return imx_ulp_clk_hw_composite(name, parent_names, num_parents, mux_present, rate_present,
+ gate_present, reg, false);
+}
+
+struct clk_hw *imx8ulp_clk_hw_composite(const char *name, const char * const *parent_names,
+ int num_parents, bool mux_present, bool rate_present,
+ bool gate_present, void __iomem *reg, bool has_swrst)
+{
+ return imx_ulp_clk_hw_composite(name, parent_names, num_parents, mux_present, rate_present,
+ gate_present, reg, has_swrst);
+}
+EXPORT_SYMBOL_GPL(imx8ulp_clk_hw_composite);
diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c
index 04e728538cef..fec34169aa5b 100644
--- a/drivers/clk/imx/clk-composite-8m.c
+++ b/drivers/clk/imx/clk-composite-8m.c
@@ -223,14 +223,19 @@ struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
div->lock = &imx_ccm_lock;
div->flags = CLK_DIVIDER_ROUND_CLOSEST;
- gate = kzalloc(sizeof(*gate), GFP_KERNEL);
- if (!gate)
- goto fail;
-
- gate_hw = &gate->hw;
- gate->reg = reg;
- gate->bit_idx = PCG_CGC_SHIFT;
- gate->lock = &imx_ccm_lock;
+ /* skip registering the gate ops if M4 is enabled */
+ if (imx_src_is_m4_enabled()) {
+ gate_hw = NULL;
+ } else {
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ goto fail;
+
+ gate_hw = &gate->hw;
+ gate->reg = reg;
+ gate->bit_idx = PCG_CGC_SHIFT;
+ gate->lock = &imx_ccm_lock;
+ }
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
mux_hw, mux_ops, div_hw,
diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c
index f16c4019f402..52baf812684d 100644
--- a/drivers/clk/imx/clk-gate2.c
+++ b/drivers/clk/imx/clk-gate2.c
@@ -8,11 +8,13 @@
#include <linux/clk-provider.h>
#include <linux/export.h>
+#include <linux/imx_sema4.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/string.h>
+#include <soc/imx/src.h>
#include "clk.h"
/**
@@ -38,9 +40,8 @@ struct clk_gate2 {
#define to_clk_gate2(_hw) container_of(_hw, struct clk_gate2, hw)
-static void clk_gate2_do_shared_clks(struct clk_hw *hw, bool enable)
+static void clk_gate2_do_hardware(struct clk_gate2 *gate, bool enable)
{
- struct clk_gate2 *gate = to_clk_gate2(hw);
u32 reg;
reg = readl(gate->reg);
@@ -50,6 +51,39 @@ static void clk_gate2_do_shared_clks(struct clk_hw *hw, bool enable)
writel(reg, gate->reg);
}
+static void clk_gate2_do_shared_clks(struct clk_hw *hw, bool enable)
+{
+ struct clk_gate2 *gate = to_clk_gate2(hw);
+
+ if (imx_src_is_m4_enabled() && clk_on_imx6sx()) {
+#ifdef CONFIG_SOC_IMX6SX
+ if (!amp_power_mutex || !shared_mem) {
+ if (enable)
+ clk_gate2_do_hardware(gate, enable);
+ return;
+ }
+
+ imx_sema4_mutex_lock(amp_power_mutex);
+ if (shared_mem->ca9_valid != SHARED_MEM_MAGIC_NUMBER ||
+ shared_mem->cm4_valid != SHARED_MEM_MAGIC_NUMBER) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+
+ if (!imx_update_shared_mem(hw, enable)) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+
+ clk_gate2_do_hardware(gate, enable);
+
+ imx_sema4_mutex_unlock(amp_power_mutex);
+#endif
+ } else {
+ clk_gate2_do_hardware(gate, enable);
+ }
+}
+
static int clk_gate2_enable(struct clk_hw *hw)
{
struct clk_gate2 *gate = to_clk_gate2(hw);
diff --git a/drivers/clk/imx/clk-imx-acm-utils.c b/drivers/clk/imx/clk-imx-acm-utils.c
new file mode 100644
index 000000000000..b923e117dd1a
--- /dev/null
+++ b/drivers/clk/imx/clk-imx-acm-utils.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright 2020 NXP
+
+#include <linux/pm_runtime.h>
+#include <linux/pm_domain.h>
+#include "clk-imx-acm-utils.h"
+
+/**
+ * clk_imx_acm_attach_pm_domains
+ */
+int clk_imx_acm_attach_pm_domains(struct device *dev,
+ struct clk_imx_acm_pm_domains *dev_pm)
+{
+ int ret;
+ int i;
+
+ dev_pm->num_domains = of_count_phandle_with_args(dev->of_node, "power-domains",
+ "#power-domain-cells");
+ if (dev_pm->num_domains <= 1)
+ return 0;
+
+ dev_pm->pd_dev = devm_kmalloc_array(dev, dev_pm->num_domains,
+ sizeof(*dev_pm->pd_dev),
+ GFP_KERNEL);
+ if (!dev_pm->pd_dev)
+ return -ENOMEM;
+
+ dev_pm->pd_dev_link = devm_kmalloc_array(dev,
+ dev_pm->num_domains,
+ sizeof(*dev_pm->pd_dev_link),
+ GFP_KERNEL);
+ if (!dev_pm->pd_dev_link)
+ return -ENOMEM;
+
+ for (i = 0; i < dev_pm->num_domains; i++) {
+ dev_pm->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i);
+ if (IS_ERR(dev_pm->pd_dev[i]))
+ return PTR_ERR(dev_pm->pd_dev[i]);
+
+ dev_pm->pd_dev_link[i] = device_link_add(dev,
+ dev_pm->pd_dev[i],
+ DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (IS_ERR(dev_pm->pd_dev_link[i])) {
+ dev_pm_domain_detach(dev_pm->pd_dev[i], false);
+ ret = PTR_ERR(dev_pm->pd_dev_link[i]);
+ goto detach_pm;
+ }
+ }
+ return 0;
+
+detach_pm:
+ while (--i >= 0) {
+ device_link_del(dev_pm->pd_dev_link[i]);
+ dev_pm_domain_detach(dev_pm->pd_dev[i], false);
+ }
+ return ret;
+}
+
+/**
+ * fsl_dev_detach_pm_domains
+ */
+int clk_imx_acm_detach_pm_domains(struct device *dev,
+ struct clk_imx_acm_pm_domains *dev_pm)
+{
+ int i;
+
+ if (dev_pm->num_domains <= 1)
+ return 0;
+
+ for (i = 0; i < dev_pm->num_domains; i++) {
+ device_link_del(dev_pm->pd_dev_link[i]);
+ dev_pm_domain_detach(dev_pm->pd_dev[i], false);
+ }
+
+ return 0;
+}
diff --git a/drivers/clk/imx/clk-imx-acm-utils.h b/drivers/clk/imx/clk-imx-acm-utils.h
new file mode 100644
index 000000000000..662e0d123a1e
--- /dev/null
+++ b/drivers/clk/imx/clk-imx-acm-utils.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright 2020 NXP */
+
+#ifndef _CLK_IMX_ACM_UTILS_H
+#define _CLK_IMX_ACM_UTILS_H
+
+#include <linux/device.h>
+
+struct clk_imx_acm_pm_domains {
+ struct device **pd_dev;
+ struct device_link **pd_dev_link;
+ int num_domains;
+};
+
+int clk_imx_acm_attach_pm_domains(struct device *dev,
+ struct clk_imx_acm_pm_domains *dev_pm);
+int clk_imx_acm_detach_pm_domains(struct device *dev,
+ struct clk_imx_acm_pm_domains *dev_pm);
+#endif /* _CLK_IMX_ACM_UTILS_H */
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index de36f58d551c..c598f65d7c4e 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -27,7 +27,8 @@ static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", "dummy",
static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "pll2_bus", };
static const char *periph_sels[] = { "periph_pre", "periph_clk2", };
static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", };
-static const char *axi_sels[] = { "periph", "pll2_pfd2_396m", "periph", "pll3_pfd1_540m", };
+static const char *axi_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_540m", };
+static const char *axi_sels[] = { "periph", "axi_alt_sel", };
static const char *audio_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll3_pfd3_454m", "pll3_usb_otg", };
static const char *gpu_axi_sels[] = { "axi", "ahb", };
static const char *pre_axi_sels[] = { "axi", "ahb", };
@@ -37,15 +38,17 @@ static const char *gpu3d_core_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_p
static const char *gpu3d_shader_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll3_pfd0_720m", };
static const char *ipu_sels[] = { "mmdc_ch0_axi", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", };
static const char *ldb_di_sels[] = { "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "mmdc_ch1_axi", "pll3_usb_otg", };
+static const char *ldb_di0_div_sels[] = { "ldb_di0_div_3_5", "ldb_di0_div_7", };
+static const char *ldb_di1_div_sels[] = { "ldb_di1_div_3_5", "ldb_di1_div_7", };
static const char *ipu_di_pre_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd1_540m", };
static const char *ipu1_di0_sels[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
static const char *ipu1_di1_sels[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
static const char *ipu2_di0_sels[] = { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
static const char *ipu2_di1_sels[] = { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
-static const char *ipu1_di0_sels_2[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf", };
-static const char *ipu1_di1_sels_2[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf", };
-static const char *ipu2_di0_sels_2[] = { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf", };
-static const char *ipu2_di1_sels_2[] = { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf", };
+static const char *ipu1_di0_sels_2[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0_div_sel", "ldb_di1_div_sel", };
+static const char *ipu1_di1_sels_2[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0_div_sel", "ldb_di1_div_sel", };
+static const char *ipu2_di0_sels_2[] = { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0_div_sel", "ldb_di1_div_sel", };
+static const char *ipu2_di1_sels_2[] = { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0_div_sel", "ldb_di1_div_sel", };
static const char *hsi_tx_sels[] = { "pll3_120m", "pll2_pfd2_396m", };
static const char *pcie_axi_sels[] = { "axi", "ahb", };
static const char *ssi_sels[] = { "pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_audio_div", };
@@ -91,6 +94,7 @@ static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
static struct clk_hw **hws;
static struct clk_hw_onecell_data *clk_hw_data;
+static void __iomem *ccm_base;
static struct clk_div_table clk_enet_ref_table[] = {
{ .val = 0, .div = 20, },
@@ -252,6 +256,11 @@ static bool pll6_bypassed(struct device_node *node)
#define CCM_CCSR 0x0c
#define CCM_CS2CDR 0x2c
+#define CCM_CSCDR3 0x3c
+#define CCM_CCGR0 0x68
+#define CCM_CCGR3 0x74
+
+#define ANATOP_PLL3_PFD 0xf0
#define CCSR_PLL3_SW_CLK_SEL BIT(0)
@@ -388,6 +397,62 @@ static void init_ldb_clks(struct device_node *np, void __iomem *ccm_base)
#define PFD2_CLKGATE BIT(23)
#define PFD3_CLKGATE BIT(31)
+/*
+ * workaround for ERR010579, when switching the clock source of IPU clock
+ * root in CCM. even setting CCGR3[CG0]=0x0 to gate off clock before
+ * switching, IPU may hang due to no IPU clock from CCM.
+ */
+static void __init init_ipu_clk(void __iomem *anatop_base)
+{
+ u32 val, origin_podf;
+
+ /* gate off the IPU1_IPU clock */
+ val = readl_relaxed(ccm_base + CCM_CCGR3);
+ val &= ~0x3;
+ writel_relaxed(val, ccm_base + CCM_CCGR3);
+
+ /* gate off IPU DCIC1/2 clocks */
+ val = readl_relaxed(ccm_base + CCM_CCGR0);
+ val &= ~(0xf << 24);
+ writel_relaxed(val, ccm_base + CCM_CCGR0);
+
+ /* set IPU_PODF to 3'b000 */
+ val = readl_relaxed(ccm_base + CCM_CSCDR3);
+ origin_podf = val & (0x7 << 11);
+ val &= ~(0x7 << 11);
+ writel_relaxed(val, ccm_base + CCM_CSCDR3);
+
+ /* disable PLL3_PFD1 */
+ val = readl_relaxed(anatop_base + ANATOP_PLL3_PFD);
+ val &= ~(0x1 << 15);
+ writel_relaxed(val, anatop_base + ANATOP_PLL3_PFD);
+
+ /* switch IPU_SEL clock to PLL3_PFD1 */
+ val = readl_relaxed(ccm_base + CCM_CSCDR3);
+ val |= (0x3 << 9);
+ writel_relaxed(val, ccm_base + CCM_CSCDR3);
+
+ /* restore the IPU PODF*/
+ val = readl_relaxed(ccm_base + CCM_CSCDR3);
+ val |= origin_podf;
+ writel_relaxed(val, ccm_base + CCM_CSCDR3);
+
+ /* enable PLL3_PFD1 */
+ val = readl_relaxed(anatop_base + ANATOP_PLL3_PFD);
+ val |= (0x1 << 15);
+ writel_relaxed(val, anatop_base + ANATOP_PLL3_PFD);
+
+ /* enable IPU1_IPU clock */
+ val = readl_relaxed(ccm_base + CCM_CCGR3);
+ val |= 0x3;
+ writel_relaxed(val, ccm_base + CCM_CCGR3);
+
+ /* enable IPU DCIC1/2 clock */
+ val = readl_relaxed(ccm_base + CCM_CCGR0);
+ val |= (0xf << 24);
+ writel_relaxed(val, ccm_base + CCM_CCGR0);
+}
+
static void disable_anatop_clocks(void __iomem *anatop_base)
{
unsigned int reg;
@@ -600,6 +665,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
np = ccm_node;
base = of_iomap(np, 0);
+ ccm_base = base;
WARN_ON(!base);
/* name reg shift width parent_names num_parents */
@@ -609,7 +675,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
hws[IMX6QDL_CLK_PERIPH2_PRE] = imx_clk_hw_mux("periph2_pre", base + 0x18, 21, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
hws[IMX6QDL_CLK_PERIPH_CLK2_SEL] = imx_clk_hw_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
hws[IMX6QDL_CLK_PERIPH2_CLK2_SEL] = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
- hws[IMX6QDL_CLK_AXI_SEL] = imx_clk_hw_mux("axi_sel", base + 0x14, 6, 2, axi_sels, ARRAY_SIZE(axi_sels));
+ hws[IMX6QDL_CLK_AXI_ALT_SEL] = imx_clk_hw_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
+ hws[IMX6QDL_CLK_AXI_SEL] = imx_clk_hw_mux("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels));
hws[IMX6QDL_CLK_ESAI_SEL] = imx_clk_hw_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels));
hws[IMX6QDL_CLK_ASRC_SEL] = imx_clk_hw_mux("asrc_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
hws[IMX6QDL_CLK_SPDIF_SEL] = imx_clk_hw_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
@@ -655,6 +722,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
hws[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_hw_mux_ldb("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels));
}
+ hws[IMX6QDL_CLK_LDB_DI0_DIV_SEL] = imx_clk_hw_mux_flags("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_LDB_DI1_DIV_SEL] = imx_clk_hw_mux_flags("ldb_di1_div_sel", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels), CLK_SET_RATE_PARENT);
hws[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_hw_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
hws[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_hw_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
hws[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_hw_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
@@ -723,6 +792,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
hws[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_hw_divider("uart_serial_podf", "uart_sel", base + 0x24, 0, 6);
hws[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0", 2, 7);
hws[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1", 2, 7);
+ hws[IMX6QDL_CLK_LDB_DI0_DIV_7] = imx_clk_hw_fixed_factor("ldb_di0_div_7", "ldb_di0", 1, 7);
+ hws[IMX6QDL_CLK_LDB_DI1_DIV_7] = imx_clk_hw_fixed_factor("ldb_di1_div_7", "ldb_di1", 1, 7);
} else {
hws[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_hw_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6);
hws[IMX6QDL_CLK_CAN_ROOT] = imx_clk_hw_divider("can_root", "pll3_60m", base + 0x20, 2, 6);
@@ -730,6 +801,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
hws[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_hw_divider("uart_serial_podf", "pll3_80m", base + 0x24, 0, 6);
hws[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
hws[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
+ hws[IMX6QDL_CLK_LDB_DI0_DIV_7] = imx_clk_hw_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7);
+ hws[IMX6QDL_CLK_LDB_DI1_DIV_7] = imx_clk_hw_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7);
}
if (clk_on_imx6dl())
@@ -915,8 +988,24 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk_hw_register_clkdev(hws[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL);
clk_set_rate(hws[IMX6QDL_CLK_PLL3_PFD1_540M]->clk, 540000000);
- if (clk_on_imx6dl())
+ if (clk_on_imx6dl()) {
+ init_ipu_clk(anatop_base);
clk_set_parent(hws[IMX6QDL_CLK_IPU1_SEL]->clk, hws[IMX6QDL_CLK_PLL3_PFD1_540M]->clk);
+ clk_set_parent(hws[IMX6QDL_CLK_AXI_ALT_SEL]->clk, hws[IMX6QDL_CLK_PLL3_PFD1_540M]->clk);
+ clk_set_parent(hws[IMX6QDL_CLK_AXI_SEL]->clk, hws[IMX6QDL_CLK_AXI_ALT_SEL]->clk);
+ /* set eim_slow to 135Mhz */
+ clk_set_rate(hws[IMX6QDL_CLK_EIM_SLOW]->clk, 135000000);
+
+ /* set epdc/pxp axi clock to 200Mhz */
+ clk_set_parent(hws[IMX6QDL_CLK_IPU2_SEL]->clk, hws[IMX6QDL_CLK_PLL2_PFD2_396M]->clk);
+ clk_set_rate(hws[IMX6QDL_CLK_IPU2]->clk, 200000000);
+ } else {
+ /* set eim_slow to 132Mhz */
+ clk_set_rate(hws[IMX6QDL_CLK_EIM_SLOW]->clk, 132000000);
+ clk_set_parent(hws[IMX6QDL_CLK_IPU1_SEL]->clk, hws[IMX6QDL_CLK_MMDC_CH0_AXI]->clk);
+
+ clk_set_parent(hws[IMX6QDL_CLK_IPU2_SEL]->clk, hws[IMX6QDL_CLK_MMDC_CH0_AXI]->clk);
+ }
clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI0_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk);
clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI1_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk);
diff --git a/drivers/clk/imx/clk-imx6sl.c b/drivers/clk/imx/clk-imx6sl.c
index 277365970320..92edc24cc041 100644
--- a/drivers/clk/imx/clk-imx6sl.c
+++ b/drivers/clk/imx/clk-imx6sl.c
@@ -433,10 +433,20 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
/* Audio-related clocks configuration */
clk_set_parent(hws[IMX6SL_CLK_SPDIF0_SEL]->clk, hws[IMX6SL_CLK_PLL3_PFD3]->clk);
+ /* Initialize Video PLLs to valid frequency (650MHz). */
+ clk_set_rate(hws[IMX6SL_CLK_PLL5_VIDEO_DIV]->clk, 650000000);
+
/* set PLL5 video as lcdif pix parent clock */
clk_set_parent(hws[IMX6SL_CLK_LCDIF_PIX_SEL]->clk,
hws[IMX6SL_CLK_PLL5_VIDEO_DIV]->clk);
+ /* Configure EPDC clocks */
+ clk_set_parent(hws[IMX6SL_CLK_EPDC_PIX_SEL]->clk,
+ hws[IMX6SL_CLK_PLL5_VIDEO_DIV]->clk);
+ clk_set_parent(hws[IMX6SL_CLK_EPDC_AXI_SEL]->clk,
+ hws[IMX6SL_CLK_PLL2_PFD2]->clk);
+ clk_set_rate(hws[IMX6SL_CLK_EPDC_AXI]->clk, 200000000);
+
clk_set_parent(hws[IMX6SL_CLK_LCDIF_AXI_SEL]->clk,
hws[IMX6SL_CLK_PLL2_PFD2]->clk);
diff --git a/drivers/clk/imx/clk-imx6sll.c b/drivers/clk/imx/clk-imx6sll.c
index 31d777f30039..d1e6428da503 100644
--- a/drivers/clk/imx/clk-imx6sll.c
+++ b/drivers/clk/imx/clk-imx6sll.c
@@ -350,6 +350,10 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
clk_set_parent(hws[IMX6SLL_CLK_PERIPH]->clk, hws[IMX6SLL_CLK_PERIPH_CLK2]->clk);
clk_set_parent(hws[IMX6SLL_CLK_PERIPH_PRE]->clk, hws[IMX6SLL_CLK_PLL2_BUS]->clk);
clk_set_parent(hws[IMX6SLL_CLK_PERIPH]->clk, hws[IMX6SLL_CLK_PERIPH_PRE]->clk);
+ /* Configure EPDC clocks */
+ clk_set_rate(hws[IMX6SLL_CLK_PLL3_PFD2]->clk, 320000000);
+ clk_set_parent(hws[IMX6SLL_CLK_EPDC_PRE_SEL]->clk,
+ hws[IMX6SLL_CLK_PLL3_PFD2]->clk);
clk_set_rate(hws[IMX6SLL_CLK_AHB]->clk, 132000000);
}
diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c
index fc1bd23d4583..2301d8fb8c76 100644
--- a/drivers/clk/imx/clk-imx6sx.c
+++ b/drivers/clk/imx/clk-imx6sx.c
@@ -11,13 +11,18 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/imx_sema4.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/types.h>
+#include <soc/imx/gpc.h>
+#include <soc/imx/src.h>
#include "clk.h"
+#define CCM_CCGR_OFFSET(index) (index * 2)
+
static const char *step_sels[] = { "osc", "pll2_pfd2_396m", };
static const char *pll1_sw_sels[] = { "pll1_sys", "step", };
static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", };
@@ -84,6 +89,12 @@ static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
static struct clk_hw **hws;
static struct clk_hw_onecell_data *clk_hw_data;
+struct imx_sema4_mutex *amp_power_mutex;
+
+static int clks_shared[MAX_SHARED_CLK_NUMBER];
+
+struct imx_shared_mem *shared_mem;
+static unsigned int shared_mem_paddr, shared_mem_size;
static const struct clk_div_table clk_enet_ref_table[] = {
{ .val = 0, .div = 20, },
@@ -117,6 +128,39 @@ static u32 share_count_ssi3;
static u32 share_count_sai1;
static u32 share_count_sai2;
+/*
+ * As IMX6SX_CLK_M4_PRE_SEL is NOT a glitchless MUX, so when
+ * M4 is trying to change its clk parent, need to ask A9 to
+ * help do it, and M4 must be hold in wfi. To avoid glitch
+ * occur, need to gate M4 clk first before switching its parent.
+ */
+void imx6sx_set_m4_highfreq(bool high_freq)
+{
+ static struct clk *m4_high_freq_sel;
+
+ imx_gpc_hold_m4_in_sleep();
+
+ clk_disable_unprepare(hws[IMX6SX_CLK_M4]->clk);
+ clk_set_parent(hws[IMX6SX_CLK_M4_SEL]->clk,
+ hws[IMX6SX_CLK_LDB_DI0]->clk);
+
+ if (high_freq) {
+ /* FIXME: m4_high_freq_sel possible used without intialization? */
+ clk_set_parent(hws[IMX6SX_CLK_M4_PRE_SEL]->clk,
+ m4_high_freq_sel);
+ } else {
+ m4_high_freq_sel = clk_get_parent(hws[IMX6SX_CLK_M4_PRE_SEL]->clk);
+ clk_set_parent(hws[IMX6SX_CLK_M4_PRE_SEL]->clk,
+ hws[IMX6SX_CLK_OSC]->clk);
+ }
+
+ clk_set_parent(hws[IMX6SX_CLK_M4_SEL]->clk,
+ hws[IMX6SX_CLK_M4_PRE_SEL]->clk);
+ clk_prepare_enable(hws[IMX6SX_CLK_M4]->clk);
+
+ imx_gpc_release_m4_in_sleep();
+}
+
static void __init imx6sx_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
@@ -182,7 +226,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clk_set_parent(hws[IMX6SX_PLL6_BYPASS]->clk, hws[IMX6SX_CLK_PLL6]->clk);
clk_set_parent(hws[IMX6SX_PLL7_BYPASS]->clk, hws[IMX6SX_CLK_PLL7]->clk);
- hws[IMX6SX_CLK_PLL1_SYS] = imx_clk_hw_gate("pll1_sys", "pll1_bypass", base + 0x00, 13);
+ hws[IMX6SX_CLK_PLL1_SYS] = imx_clk_hw_fixed_factor("pll1_sys", "pll1_bypass", 1, 1);
hws[IMX6SX_CLK_PLL2_BUS] = imx_clk_hw_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
hws[IMX6SX_CLK_PLL3_USB_OTG] = imx_clk_hw_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
hws[IMX6SX_CLK_PLL4_AUDIO] = imx_clk_hw_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
@@ -398,7 +442,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
hws[IMX6SX_CLK_GPT_BUS] = imx_clk_hw_gate2("gpt_bus", "perclk", base + 0x6c, 20);
hws[IMX6SX_CLK_GPT_SERIAL] = imx_clk_hw_gate2("gpt_serial", "perclk", base + 0x6c, 22);
hws[IMX6SX_CLK_GPU] = imx_clk_hw_gate2("gpu", "gpu_core_podf", base + 0x6c, 26);
- hws[IMX6SX_CLK_OCRAM_S] = imx_clk_hw_gate2("ocram_s", "ahb", base + 0x6c, 28);
+ hws[IMX6SX_CLK_OCRAM_S] = imx_clk_hw_gate2_flags("ocram_s", "ahb", base + 0x6c, 28, CLK_IS_CRITICAL);
hws[IMX6SX_CLK_CANFD] = imx_clk_hw_gate2("canfd", "can_podf", base + 0x6c, 30);
/* CCGR2 */
@@ -482,13 +526,59 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
hws[IMX6SX_CLK_CKO1] = imx_clk_hw_gate("cko1", "cko1_podf", base + 0x60, 7);
hws[IMX6SX_CLK_CKO2] = imx_clk_hw_gate("cko2", "cko2_podf", base + 0x60, 24);
+ /* get those shared clk nodes if M4 is active */
+ if (imx_src_is_m4_enabled()) {
+ u32 num;
+
+ of_property_read_u32(np, "fsl,shared-clks-number", &num);
+ if (num > MAX_SHARED_CLK_NUMBER)
+ pr_err("clk: shared clk nodes exceed the max number!\n");
+ of_property_read_u32_array(np, "fsl,shared-clks-index",
+ clks_shared, num);
+ if (of_property_read_u32(np, "fsl,shared-mem-addr",
+ &shared_mem_paddr))
+ pr_err("clk: fsl,shared-mem-addr NOT found!\n");
+ if (of_property_read_u32(np, "fsl,shared-mem-size",
+ &shared_mem_size))
+ pr_err("clk: fsl,shared-mem-size NOT found!\n");
+ }
+
/* mask handshake of mmdc */
imx_mmdc_mask_handshake(base, 0);
imx_check_clk_hws(hws, IMX6SX_CLK_CLK_END);
+ /*
+ * QSPI2/GPMI_IO share the same clock source but with the
+ * different gate, need explicitely gate the QSPI2 & GPMI_IO
+ * during the clock init phase according to the SOC design.
+ */
+ if (!imx_src_is_m4_enabled()) {
+ writel_relaxed(readl_relaxed(base + 0x78) &
+ ~(3 << CCM_CCGR_OFFSET(5)), base + 0x78);
+ writel_relaxed(readl_relaxed(base + 0x78) &
+ ~(3 << CCM_CCGR_OFFSET(14)), base + 0x78);
+ }
+
+
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
+ /*
+ * As some of the modules need to access ocotp in MSL,
+ * need to make sure ocotp clk(CCM_CCGR2_CG6) is enabled
+ * during MSL, as on i.MX6SX, accessing OCOTP registers
+ * needs its clk on, it will be disabled by clk late
+ * init and managed by ocotp driver.
+ */
+ writel_relaxed(readl_relaxed(base + 0x70) | 1 << 12, base + 0x70);
+
+ /* maintain M4 usecount */
+ if (imx_src_is_m4_enabled())
+ clk_prepare_enable(hws[IMX6SX_CLK_M4]->clk);
+
+ /* set perclk to from OSC */
+ clk_set_parent(hws[IMX6SX_CLK_PERCLK_SEL]->clk, hws[IMX6SX_CLK_OSC]->clk);
+
if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
clk_prepare_enable(hws[IMX6SX_CLK_USBPHY1_GATE]->clk);
clk_prepare_enable(hws[IMX6SX_CLK_USBPHY2_GATE]->clk);
@@ -520,7 +610,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clk_set_rate(hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk, 393216000);
clk_set_parent(hws[IMX6SX_CLK_SPDIF_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
- clk_set_rate(hws[IMX6SX_CLK_SPDIF_PODF]->clk, 98304000);
+ clk_set_rate(hws[IMX6SX_CLK_SPDIF_PODF]->clk, 24576000);
clk_set_parent(hws[IMX6SX_CLK_AUDIO_SEL]->clk, hws[IMX6SX_CLK_PLL3_USB_OTG]->clk);
clk_set_rate(hws[IMX6SX_CLK_AUDIO_PODF]->clk, 24000000);
@@ -535,6 +625,12 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clk_set_parent(hws[IMX6SX_CLK_ESAI_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
clk_set_rate(hws[IMX6SX_CLK_ESAI_PODF]->clk, 24576000);
+ /* Set the UART parent if needed. */
+ if (uart_from_osc)
+ clk_set_parent(hws[IMX6SX_CLK_UART_SEL]->clk, hws[IMX6SX_CLK_OSC]->clk);
+ else
+ clk_set_parent(hws[IMX6SX_CLK_UART_SEL]->clk, hws[IMX6SX_CLK_PLL3_80M]->clk);
+
/* Set parent clock for vadc */
clk_set_parent(hws[IMX6SX_CLK_VID_SEL]->clk, hws[IMX6SX_CLK_PLL3_USB_OTG]->clk);
@@ -544,6 +640,9 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
/* Update gpu clock from default 528M to 720M */
clk_set_parent(hws[IMX6SX_CLK_GPU_CORE_SEL]->clk, hws[IMX6SX_CLK_PLL3_PFD0]->clk);
clk_set_parent(hws[IMX6SX_CLK_GPU_AXI_SEL]->clk, hws[IMX6SX_CLK_PLL3_PFD0]->clk);
+ if (!imx_src_is_m4_enabled())
+ /* default parent of can_sel clock is invalid, manually set it here */
+ clk_set_parent(hws[IMX6SX_CLK_CAN_SEL]->clk, hws[IMX6SX_CLK_PLL3_60M]->clk);
clk_set_parent(hws[IMX6SX_CLK_QSPI1_SEL]->clk, hws[IMX6SX_CLK_PLL2_BUS]->clk);
clk_set_parent(hws[IMX6SX_CLK_QSPI2_SEL]->clk, hws[IMX6SX_CLK_PLL2_BUS]->clk);
@@ -551,3 +650,64 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
imx_register_uart_clocks(2);
}
CLK_OF_DECLARE(imx6sx, "fsl,imx6sx-ccm", imx6sx_clocks_init);
+
+int imx_update_shared_mem(struct clk_hw *hw, bool enable)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(clks_shared); i++) {
+ if (shared_mem->imx_clk[i].self == hw->clk)
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(clks_shared))
+ return 1;
+
+ /* update ca9 clk status in shared memory */
+ if (enable)
+ shared_mem->imx_clk[i].ca9_enabled = 1;
+ else
+ shared_mem->imx_clk[i].ca9_enabled = 0;
+
+ if (shared_mem->imx_clk[i].cm4_enabled == 0)
+ return 1;
+
+ return 0;
+}
+
+static int __init imx_amp_power_init(void)
+{
+ int i;
+ void __iomem *shared_mem_base;
+
+ if (!(imx_src_is_m4_enabled() && clk_on_imx6sx()))
+ return 0;
+
+ amp_power_mutex = imx_sema4_mutex_create(0, MCC_POWER_SHMEM_NUMBER);
+
+ shared_mem_base = ioremap(shared_mem_paddr, shared_mem_size);
+
+ if (!amp_power_mutex) {
+ pr_err("Failed to create sema4 mutex!\n");
+ return 0;
+ }
+
+ shared_mem = (struct imx_shared_mem *)shared_mem_base;
+
+ for (i = 0; i < ARRAY_SIZE(clks_shared); i++) {
+ shared_mem->imx_clk[i].self = hws[clks_shared[i]]->clk;
+ shared_mem->imx_clk[i].ca9_enabled = 1;
+ pr_debug("%d: name %s, addr 0x%x\n", i,
+ __clk_get_name(shared_mem->imx_clk[i].self),
+ (u32)&(shared_mem->imx_clk[i]));
+ }
+ /* enable amp power management */
+ shared_mem->ca9_valid = SHARED_MEM_MAGIC_NUMBER;
+
+ pr_info("A9-M4 sema4 num %d, A9-M4 magic number 0x%x - 0x%x.\n",
+ amp_power_mutex->gate_num, shared_mem->ca9_valid,
+ shared_mem->cm4_valid);
+
+ return 0;
+}
+late_initcall(imx_amp_power_init);
diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c
index 206e4c43f68f..427f1310a88f 100644
--- a/drivers/clk/imx/clk-imx6ul.c
+++ b/drivers/clk/imx/clk-imx6ul.c
@@ -495,6 +495,12 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clk_set_rate(hws[IMX6UL_CLK_ENET2_REF]->clk, 50000000);
clk_set_rate(hws[IMX6UL_CLK_CSI]->clk, 24000000);
+ /* Set the UART parent if needed */
+ if (uart_from_osc)
+ clk_set_parent(hws[IMX6UL_CLK_UART_SEL]->clk, hws[IMX6UL_CLK_OSC]->clk);
+ else
+ clk_set_parent(hws[IMX6UL_CLK_UART_SEL]->clk, hws[IMX6UL_CLK_PLL3_80M]->clk);
+
if (clk_on_imx6ull())
clk_prepare_enable(hws[IMX6UL_CLK_AIPSTZ3]->clk);
diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index 3f6fd7ef2a68..13b6702cc035 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -15,6 +15,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/types.h>
+#include <soc/imx/src.h>
#include "clk.h"
@@ -24,6 +25,7 @@ static u32 share_count_sai3;
static u32 share_count_nand;
static u32 share_count_enet1;
static u32 share_count_enet2;
+static u32 share_count_pxp;
static const struct clk_div_table test_div_table[] = {
{ .val = 3, .div = 1, },
@@ -498,14 +500,14 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
hws[IMX7D_ENET_AXI_ROOT_SRC] = imx_clk_hw_mux2_flags("enet_axi_src", base + 0x8900, 24, 3, enet_axi_sel, ARRAY_SIZE(enet_axi_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_NAND_USDHC_BUS_ROOT_SRC] = imx_clk_hw_mux2_flags("nand_usdhc_src", base + 0x8980, 24, 3, nand_usdhc_bus_sel, ARRAY_SIZE(nand_usdhc_bus_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_DRAM_PHYM_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_phym_src", base + 0x9800, 24, 1, dram_phym_sel, ARRAY_SIZE(dram_phym_sel), CLK_SET_PARENT_GATE);
- hws[IMX7D_DRAM_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel), CLK_SET_PARENT_GATE);
+ hws[IMX7D_DRAM_ROOT_SRC] = imx_clk_hw_mux2("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel));
hws[IMX7D_DRAM_PHYM_ALT_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_phym_alt_src", base + 0xa000, 24, 3, dram_phym_alt_sel, ARRAY_SIZE(dram_phym_alt_sel), CLK_SET_PARENT_GATE);
- hws[IMX7D_DRAM_ALT_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel), CLK_SET_PARENT_GATE);
+ hws[IMX7D_DRAM_ALT_ROOT_SRC] = imx_clk_hw_mux2("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel));
hws[IMX7D_USB_HSIC_ROOT_SRC] = imx_clk_hw_mux2_flags("usb_hsic_src", base + 0xa100, 24, 3, usb_hsic_sel, ARRAY_SIZE(usb_hsic_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_PCIE_CTRL_ROOT_SRC] = imx_clk_hw_mux2_flags("pcie_ctrl_src", base + 0xa180, 24, 3, pcie_ctrl_sel, ARRAY_SIZE(pcie_ctrl_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_PCIE_PHY_ROOT_SRC] = imx_clk_hw_mux2_flags("pcie_phy_src", base + 0xa200, 24, 3, pcie_phy_sel, ARRAY_SIZE(pcie_phy_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_EPDC_PIXEL_ROOT_SRC] = imx_clk_hw_mux2_flags("epdc_pixel_src", base + 0xa280, 24, 3, epdc_pixel_sel, ARRAY_SIZE(epdc_pixel_sel), CLK_SET_PARENT_GATE);
- hws[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_hw_mux2_flags("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel), CLK_SET_PARENT_GATE);
+ hws[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_hw_mux2_flags("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel), CLK_SET_PARENT_GATE | CLK_SET_RATE_PARENT);
hws[IMX7D_MIPI_DSI_ROOT_SRC] = imx_clk_hw_mux2_flags("mipi_dsi_src", base + 0xa380, 24, 3, mipi_dsi_sel, ARRAY_SIZE(mipi_dsi_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_MIPI_CSI_ROOT_SRC] = imx_clk_hw_mux2_flags("mipi_csi_src", base + 0xa400, 24, 3, mipi_csi_sel, ARRAY_SIZE(mipi_csi_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_MIPI_DPHY_ROOT_SRC] = imx_clk_hw_mux2_flags("mipi_dphy_src", base + 0xa480, 24, 3, mipi_dphy_sel, ARRAY_SIZE(mipi_dphy_sel), CLK_SET_PARENT_GATE);
@@ -782,7 +784,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
hws[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_hw_gate2_flags("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
hws[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_hw_gate2_flags("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
hws[IMX7D_OCOTP_CLK] = imx_clk_hw_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0);
- hws[IMX7D_SNVS_CLK] = imx_clk_hw_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0);
+ hws[IMX7D_SNVS_CLK] = imx_clk_hw_gate2_flags("snvs_clk", "ipg_root_clk", base + 0x4250, 0, CLK_IS_CRITICAL);
hws[IMX7D_MU_ROOT_CLK] = imx_clk_hw_gate4("mu_root_clk", "ipg_root_clk", base + 0x4270, 0);
hws[IMX7D_CAAM_CLK] = imx_clk_hw_gate4("caam_clk", "ipg_root_clk", base + 0x4240, 0);
hws[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_hw_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0);
@@ -791,7 +793,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
hws[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_hw_gate4("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0);
hws[IMX7D_EPDC_PIXEL_ROOT_CLK] = imx_clk_hw_gate4("epdc_pixel_root_clk", "epdc_pixel_post_div", base + 0x44a0, 0);
hws[IMX7D_LCDIF_PIXEL_ROOT_CLK] = imx_clk_hw_gate4("lcdif_pixel_root_clk", "lcdif_pixel_post_div", base + 0x44b0, 0);
- hws[IMX7D_PXP_CLK] = imx_clk_hw_gate4("pxp_clk", "main_axi_root_clk", base + 0x44c0, 0);
hws[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_hw_gate4("mipi_dsi_root_clk", "mipi_dsi_post_div", base + 0x4650, 0);
hws[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_hw_gate4("mipi_csi_root_clk", "mipi_csi_post_div", base + 0x4640, 0);
hws[IMX7D_MIPI_DPHY_ROOT_CLK] = imx_clk_hw_gate4("mipi_dphy_root_clk", "mipi_dphy_post_div", base + 0x4660, 0);
@@ -854,6 +855,8 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
hws[IMX7D_USB_PHY1_CLK] = imx_clk_hw_gate4("usb_phy1_clk", "pll_usb1_main_clk", base + 0x46a0, 0);
hws[IMX7D_USB_PHY2_CLK] = imx_clk_hw_gate4("usb_phy2_clk", "pll_usb_main_clk", base + 0x46b0, 0);
hws[IMX7D_ADC_ROOT_CLK] = imx_clk_hw_gate4("adc_root_clk", "ipg_root_clk", base + 0x4200, 0);
+ hws[IMX7D_PXP_IPG_CLK] = imx_clk_hw_gate2_shared2("pxp_ipg_clk", "ipg_root_clk", base + 0x44c0, 0, &share_count_pxp);
+ hws[IMX7D_PXP_AXI_CLK] = imx_clk_hw_gate2_shared2("pxp_axi_clk", "main_axi_root_clk", base + 0x44c0, 0, &share_count_pxp);
hws[IMX7D_GPT_3M_CLK] = imx_clk_hw_fixed_factor("gpt_3m", "osc", 1, 8);
@@ -876,6 +879,12 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clk_set_parent(hws[IMX7D_MIPI_CSI_ROOT_SRC]->clk, hws[IMX7D_PLL_SYS_PFD3_CLK]->clk);
+ if (imx_src_is_m4_enabled()) {
+ clk_set_parent(hws[IMX7D_ARM_M4_ROOT_SRC]->clk, hws[IMX7D_PLL_SYS_MAIN_240M_CLK]->clk);
+ clk_prepare_enable(hws[IMX7D_ARM_M4_ROOT_CLK]->clk);
+ clk_prepare_enable(hws[IMX7D_UART2_ROOT_CLK]->clk);
+ }
+
/* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */
clk_set_parent(hws[IMX7D_GPT1_ROOT_SRC]->clk, hws[IMX7D_OSC_24M_CLK]->clk);
@@ -883,7 +892,9 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
hws[IMX7D_USB1_MAIN_480M_CLK] = imx_clk_hw_fixed_factor("pll_usb1_main_clk", "osc", 20, 1);
hws[IMX7D_USB_MAIN_480M_CLK] = imx_clk_hw_fixed_factor("pll_usb_main_clk", "osc", 20, 1);
- imx_register_uart_clocks(7);
+ /* set parent of EPDC pixel clock */
+ clk_set_parent(hws[IMX7D_EPDC_PIXEL_ROOT_SRC]->clk, hws[IMX7D_PLL_SYS_MAIN_CLK]->clk);
+ imx_register_uart_clocks(7);
}
CLK_OF_DECLARE(imx7d, "fsl,imx7d-ccm", imx7d_clocks_init);
diff --git a/drivers/clk/imx/clk-imx7ulp.c b/drivers/clk/imx/clk-imx7ulp.c
index 779e09105da7..b6e45e77ee39 100644
--- a/drivers/clk/imx/clk-imx7ulp.c
+++ b/drivers/clk/imx/clk-imx7ulp.c
@@ -78,20 +78,20 @@ static void __init imx7ulp_clk_scg1_init(struct device_node *np)
hws[IMX7ULP_CLK_SPLL_PRE_DIV] = imx_clk_hw_divider_flags("spll_pre_div", "spll_pre_sel", base + 0x608, 8, 3, CLK_SET_RATE_GATE);
/* name parent_name base */
- hws[IMX7ULP_CLK_APLL] = imx_clk_hw_pllv4("apll", "apll_pre_div", base + 0x500);
- hws[IMX7ULP_CLK_SPLL] = imx_clk_hw_pllv4("spll", "spll_pre_div", base + 0x600);
+ hws[IMX7ULP_CLK_APLL] = imx_clk_hw_pllv4(IMX_PLLV4_IMX7ULP, "apll", "apll_pre_div", base + 0x500);
+ hws[IMX7ULP_CLK_SPLL] = imx_clk_hw_pllv4(IMX_PLLV4_IMX7ULP, "spll", "spll_pre_div", base + 0x600);
/* APLL PFDs */
- hws[IMX7ULP_CLK_APLL_PFD0] = imx_clk_hw_pfdv2("apll_pfd0", "apll", base + 0x50c, 0);
- hws[IMX7ULP_CLK_APLL_PFD1] = imx_clk_hw_pfdv2("apll_pfd1", "apll", base + 0x50c, 1);
- hws[IMX7ULP_CLK_APLL_PFD2] = imx_clk_hw_pfdv2("apll_pfd2", "apll", base + 0x50c, 2);
- hws[IMX7ULP_CLK_APLL_PFD3] = imx_clk_hw_pfdv2("apll_pfd3", "apll", base + 0x50c, 3);
+ hws[IMX7ULP_CLK_APLL_PFD0] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX7ULP, "apll_pfd0", "apll", base + 0x50c, 0);
+ hws[IMX7ULP_CLK_APLL_PFD1] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX7ULP, "apll_pfd1", "apll", base + 0x50c, 1);
+ hws[IMX7ULP_CLK_APLL_PFD2] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX7ULP, "apll_pfd2", "apll", base + 0x50c, 2);
+ hws[IMX7ULP_CLK_APLL_PFD3] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX7ULP, "apll_pfd3", "apll", base + 0x50c, 3);
/* SPLL PFDs */
- hws[IMX7ULP_CLK_SPLL_PFD0] = imx_clk_hw_pfdv2("spll_pfd0", "spll", base + 0x60C, 0);
- hws[IMX7ULP_CLK_SPLL_PFD1] = imx_clk_hw_pfdv2("spll_pfd1", "spll", base + 0x60C, 1);
- hws[IMX7ULP_CLK_SPLL_PFD2] = imx_clk_hw_pfdv2("spll_pfd2", "spll", base + 0x60C, 2);
- hws[IMX7ULP_CLK_SPLL_PFD3] = imx_clk_hw_pfdv2("spll_pfd3", "spll", base + 0x60C, 3);
+ hws[IMX7ULP_CLK_SPLL_PFD0] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX7ULP, "spll_pfd0", "spll", base + 0x60C, 0);
+ hws[IMX7ULP_CLK_SPLL_PFD1] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX7ULP, "spll_pfd1", "spll", base + 0x60C, 1);
+ hws[IMX7ULP_CLK_SPLL_PFD2] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX7ULP, "spll_pfd2", "spll", base + 0x60C, 2);
+ hws[IMX7ULP_CLK_SPLL_PFD3] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX7ULP, "spll_pfd3", "spll", base + 0x60C, 3);
/* PLL Mux */
hws[IMX7ULP_CLK_APLL_PFD_SEL] = imx_clk_hw_mux_flags("apll_pfd_sel", base + 0x508, 14, 2, apll_pfd_sels, ARRAY_SIZE(apll_pfd_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
diff --git a/drivers/clk/imx/clk-imx8dxl-acm.c b/drivers/clk/imx/clk-imx8dxl-acm.c
new file mode 100644
index 000000000000..b11254522bc5
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8dxl-acm.c
@@ -0,0 +1,235 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019~2020 NXP
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+
+#include "clk.h"
+#include "clk-scu.h"
+#include "clk-imx-acm-utils.h"
+
+#include <dt-bindings/clock/imx8-clock.h>
+
+struct imx8dxl_acm_priv {
+ struct clk_imx_acm_pm_domains dev_pm;
+ void __iomem *reg;
+ u32 regs[0x20];
+};
+
+static const char *aud_clk_sels[] = {
+ "aud_rec_clk0_lpcg_clk",
+ "aud_rec_clk1_lpcg_clk",
+ "ext_aud_mclk0",
+ "ext_aud_mclk1",
+ "dummy",
+ "dummy",
+ "dummy",
+ "dummy",
+ "spdif0_rx",
+ "sai0_rx_bclk",
+ "sai0_tx_bclk",
+ "sai1_rx_bclk",
+ "sai1_tx_bclk",
+ "sai2_rx_bclk",
+ "sai3_rx_bclk",
+};
+
+static const char *mclk_out_sels[] = {
+ "aud_rec_clk0_lpcg_clk",
+ "aud_rec_clk1_lpcg_clk",
+ "dummy",
+ "dummy",
+ "spdif0_rx",
+ "dummy",
+ "dummy",
+ "dummy",
+};
+
+static const char *sai_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static const char *spdif_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static const char *mqs_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static int imx8dxl_acm_clk_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct clk_onecell_data *clk_data;
+ struct imx8dxl_acm_priv *priv;
+ struct resource *res;
+ struct clk **clks;
+ void __iomem *base;
+ int ret;
+ int i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!base)
+ return -ENOMEM;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->reg = base;
+
+ platform_set_drvdata(pdev, priv);
+
+ clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->clks = devm_kcalloc(&pdev->dev, IMX_ADMA_ACM_CLK_END,
+ sizeof(*clk_data->clks), GFP_KERNEL);
+ if (!clk_data->clks)
+ return -ENOMEM;
+
+ clk_data->clk_num = IMX_ADMA_ACM_CLK_END;
+
+ clks = clk_data->clks;
+
+ ret = clk_imx_acm_attach_pm_domains(&pdev->dev, &priv->dev_pm);
+ if (ret)
+ return ret;
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
+ clks[IMX_ADMA_EXT_AUD_MCLK0] = imx_clk_fixed("ext_aud_mclk0", 0);
+ clks[IMX_ADMA_EXT_AUD_MCLK1] = imx_clk_fixed("ext_aud_mclk1", 0);
+ clks[IMX_ADMA_SPDIF0_RX] = imx_clk_fixed("spdif0_rx", 0);
+ clks[IMX_ADMA_SAI0_RX_BCLK] = imx_clk_fixed("sai0_rx_bclk", 0);
+ clks[IMX_ADMA_SAI0_TX_BCLK] = imx_clk_fixed("sai0_tx_bclk", 0);
+ clks[IMX_ADMA_SAI1_RX_BCLK] = imx_clk_fixed("sai1_rx_bclk", 0);
+ clks[IMX_ADMA_SAI1_TX_BCLK] = imx_clk_fixed("sai1_tx_bclk", 0);
+ clks[IMX_ADMA_SAI2_RX_BCLK] = imx_clk_fixed("sai2_rx_bclk", 0);
+ clks[IMX_ADMA_SAI3_RX_BCLK] = imx_clk_fixed("sai3_rx_bclk", 0);
+
+ clks[IMX_ADMA_ACM_AUD_CLK0_SEL] = imx_dev_clk_mux(dev, "acm_aud_clk0_sel", base+0x000000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels));
+ clks[IMX_ADMA_ACM_AUD_CLK1_SEL] = imx_dev_clk_mux(dev, "acm_aud_clk1_sel", base+0x010000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels));
+
+ clks[IMX_ADMA_ACM_MCLKOUT0_SEL] = imx_dev_clk_mux(dev, "acm_mclkout0_sel", base+0x020000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels));
+ clks[IMX_ADMA_ACM_MCLKOUT1_SEL] = imx_dev_clk_mux(dev, "acm_mclkout1_sel", base+0x030000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels));
+
+ clks[IMX_ADMA_ACM_SAI0_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai0_mclk_sel", base+0x0E0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI1_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai1_mclk_sel", base+0x0F0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI2_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai2_mclk_sel", base+0x100000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI3_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai3_mclk_sel", base+0x110000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+
+ clks[IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL] = imx_dev_clk_mux(dev, "acm_spdif0_mclk_sel", base+0x1A0000, 0, 2, spdif_mclk_sels, ARRAY_SIZE(spdif_mclk_sels));
+ clks[IMX_ADMA_ACM_MQS_TX_CLK_SEL] = imx_dev_clk_mux(dev, "acm_mqs_mclk_sel", base+0x1C0000, 0, 2, mqs_mclk_sels, ARRAY_SIZE(mqs_mclk_sels));
+
+ for (i = 0; i < clk_data->clk_num; i++) {
+ if (IS_ERR(clks[i]))
+ pr_warn("i.MX clk %u: register failed with %ld\n",
+ i, PTR_ERR(clks[i]));
+ }
+
+ ret = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+
+ pm_runtime_put_sync(&pdev->dev);
+
+ return ret;
+}
+
+static int imx8dxl_acm_clk_remove(struct platform_device *pdev)
+{
+ struct imx8dxl_acm_priv *priv = dev_get_drvdata(&pdev->dev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ clk_imx_acm_detach_pm_domains(&pdev->dev, &priv->dev_pm);
+
+ return 0;
+}
+
+static const struct of_device_id imx8dxl_acm_match[] = {
+ { .compatible = "nxp,imx8dxl-acm", },
+ { /* sentinel */ }
+};
+
+static int __maybe_unused imx8dxl_acm_runtime_suspend(struct device *dev)
+{
+ struct imx8dxl_acm_priv *priv = dev_get_drvdata(dev);
+
+ priv->regs[0] = readl_relaxed(priv->reg + 0x000000);
+ priv->regs[1] = readl_relaxed(priv->reg + 0x010000);
+ priv->regs[2] = readl_relaxed(priv->reg + 0x020000);
+ priv->regs[3] = readl_relaxed(priv->reg + 0x030000);
+ priv->regs[14] = readl_relaxed(priv->reg + 0x0E0000);
+ priv->regs[15] = readl_relaxed(priv->reg + 0x0F0000);
+ priv->regs[16] = readl_relaxed(priv->reg + 0x100000);
+ priv->regs[17] = readl_relaxed(priv->reg + 0x110000);
+ priv->regs[26] = readl_relaxed(priv->reg + 0x1A0000);
+ priv->regs[28] = readl_relaxed(priv->reg + 0x1C0000);
+
+ return 0;
+}
+
+static int __maybe_unused imx8dxl_acm_runtime_resume(struct device *dev)
+{
+ struct imx8dxl_acm_priv *priv = dev_get_drvdata(dev);
+
+ writel_relaxed(priv->regs[0], priv->reg + 0x000000);
+ writel_relaxed(priv->regs[1], priv->reg + 0x010000);
+ writel_relaxed(priv->regs[2], priv->reg + 0x020000);
+ writel_relaxed(priv->regs[3], priv->reg + 0x030000);
+ writel_relaxed(priv->regs[14], priv->reg + 0x0E0000);
+ writel_relaxed(priv->regs[15], priv->reg + 0x0F0000);
+ writel_relaxed(priv->regs[16], priv->reg + 0x100000);
+ writel_relaxed(priv->regs[17], priv->reg + 0x110000);
+ writel_relaxed(priv->regs[26], priv->reg + 0x1A0000);
+ writel_relaxed(priv->regs[28], priv->reg + 0x1C0000);
+
+ return 0;
+}
+
+const struct dev_pm_ops imx8dxl_acm_pm_ops = {
+ SET_RUNTIME_PM_OPS(imx8dxl_acm_runtime_suspend,
+ imx8dxl_acm_runtime_resume, NULL)
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
+static struct platform_driver imx8dxl_acm_clk_driver = {
+ .driver = {
+ .name = "imx8dxl-acm",
+ .of_match_table = imx8dxl_acm_match,
+ .pm = &imx8dxl_acm_pm_ops,
+ .suppress_bind_attrs = true,
+ },
+ .probe = imx8dxl_acm_clk_probe,
+ .remove = imx8dxl_acm_clk_remove,
+};
+
+static int __init imx8dxl_acm_init(void)
+{
+ return platform_driver_register(&imx8dxl_acm_clk_driver);
+}
+fs_initcall(imx8dxl_acm_init);
diff --git a/drivers/clk/imx/clk-imx8dxl-rsrc.c b/drivers/clk/imx/clk-imx8dxl-rsrc.c
new file mode 100644
index 000000000000..084bad519846
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8dxl-rsrc.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019~2020 NXP
+ */
+
+#include <dt-bindings/firmware/imx/rsrc.h>
+
+#include "clk-scu.h"
+
+/* Keep sorted in the ascending order */
+static u32 imx8dxl_clk_scu_rsrc_table[] = {
+ IMX_SC_R_SPI_0,
+ IMX_SC_R_SPI_1,
+ IMX_SC_R_SPI_2,
+ IMX_SC_R_SPI_3,
+ IMX_SC_R_UART_0,
+ IMX_SC_R_UART_1,
+ IMX_SC_R_UART_2,
+ IMX_SC_R_UART_3,
+ IMX_SC_R_I2C_0,
+ IMX_SC_R_I2C_1,
+ IMX_SC_R_I2C_2,
+ IMX_SC_R_I2C_3,
+ IMX_SC_R_ADC_0,
+ IMX_SC_R_FTM_0,
+ IMX_SC_R_FTM_1,
+ IMX_SC_R_CAN_0,
+ IMX_SC_R_LCD_0,
+ IMX_SC_R_LCD_0_PWM_0,
+ IMX_SC_R_PWM_0,
+ IMX_SC_R_PWM_1,
+ IMX_SC_R_PWM_2,
+ IMX_SC_R_PWM_3,
+ IMX_SC_R_PWM_4,
+ IMX_SC_R_PWM_5,
+ IMX_SC_R_PWM_6,
+ IMX_SC_R_PWM_7,
+ IMX_SC_R_GPT_0,
+ IMX_SC_R_GPT_1,
+ IMX_SC_R_GPT_2,
+ IMX_SC_R_GPT_3,
+ IMX_SC_R_GPT_4,
+ IMX_SC_R_FSPI_0,
+ IMX_SC_R_FSPI_1,
+ IMX_SC_R_SDHC_0,
+ IMX_SC_R_SDHC_1,
+ IMX_SC_R_SDHC_2,
+ IMX_SC_R_ENET_0,
+ IMX_SC_R_ENET_1,
+ IMX_SC_R_USB_1,
+ IMX_SC_R_NAND,
+ IMX_SC_R_M4_0_I2C,
+ IMX_SC_R_M4_0_UART,
+ IMX_SC_R_ELCDIF_PLL,
+ IMX_SC_R_AUDIO_PLL_0,
+ IMX_SC_R_AUDIO_PLL_1,
+ IMX_SC_R_AUDIO_CLK_0,
+ IMX_SC_R_AUDIO_CLK_1,
+ IMX_SC_R_A35
+};
+
+const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8dxl = {
+ .rsrc = imx8dxl_clk_scu_rsrc_table,
+ .num = ARRAY_SIZE(imx8dxl_clk_scu_rsrc_table),
+};
diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c
index e92621fa8b9c..5a9f84ae22ab 100644
--- a/drivers/clk/imx/clk-imx8mm.c
+++ b/drivers/clk/imx/clk-imx8mm.c
@@ -4,7 +4,9 @@
*/
#include <dt-bindings/clock/imx8mm-clock.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/debugfs.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -12,6 +14,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <soc/imx/soc.h>
#include "clk.h"
@@ -296,6 +299,34 @@ static const char * const clkout_sels[] = {"audio_pll1_out", "audio_pll2_out", "
static struct clk_hw_onecell_data *clk_hw_data;
static struct clk_hw **hws;
+static int imx_clk_init_on(struct device_node *np,
+ struct clk_hw * const clks[])
+{
+ u32 *array;
+ int i, ret, elems;
+
+ elems = of_property_count_u32_elems(np, "init-on-array");
+ if (elems < 0)
+ return elems;
+ array = kcalloc(elems, sizeof(elems), GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(np, "init-on-array", array, elems);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < elems; i++) {
+ ret = clk_prepare_enable(clks[array[i]]->clk);
+ if (ret)
+ pr_err("clk_prepare_enable failed %d\n", array[i]);
+ }
+
+ kfree(array);
+
+ return 0;
+}
+
static int imx8mm_clocks_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -303,6 +334,8 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
void __iomem *base;
int ret;
+ check_m4_enabled();
+
clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
IMX8MM_CLK_END), GFP_KERNEL);
if (WARN_ON(!clk_hw_data))
@@ -366,45 +399,29 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
hws[IMX8MM_SYS_PLL3_OUT] = imx_clk_hw_gate("sys_pll3_out", "sys_pll3_bypass", base + 0x114, 11);
/* SYS PLL1 fixed output */
- hws[IMX8MM_SYS_PLL1_40M_CG] = imx_clk_hw_gate("sys_pll1_40m_cg", "sys_pll1", base + 0x94, 27);
- hws[IMX8MM_SYS_PLL1_80M_CG] = imx_clk_hw_gate("sys_pll1_80m_cg", "sys_pll1", base + 0x94, 25);
- hws[IMX8MM_SYS_PLL1_100M_CG] = imx_clk_hw_gate("sys_pll1_100m_cg", "sys_pll1", base + 0x94, 23);
- hws[IMX8MM_SYS_PLL1_133M_CG] = imx_clk_hw_gate("sys_pll1_133m_cg", "sys_pll1", base + 0x94, 21);
- hws[IMX8MM_SYS_PLL1_160M_CG] = imx_clk_hw_gate("sys_pll1_160m_cg", "sys_pll1", base + 0x94, 19);
- hws[IMX8MM_SYS_PLL1_200M_CG] = imx_clk_hw_gate("sys_pll1_200m_cg", "sys_pll1", base + 0x94, 17);
- hws[IMX8MM_SYS_PLL1_266M_CG] = imx_clk_hw_gate("sys_pll1_266m_cg", "sys_pll1", base + 0x94, 15);
- hws[IMX8MM_SYS_PLL1_400M_CG] = imx_clk_hw_gate("sys_pll1_400m_cg", "sys_pll1", base + 0x94, 13);
hws[IMX8MM_SYS_PLL1_OUT] = imx_clk_hw_gate("sys_pll1_out", "sys_pll1", base + 0x94, 11);
- hws[IMX8MM_SYS_PLL1_40M] = imx_clk_hw_fixed_factor("sys_pll1_40m", "sys_pll1_40m_cg", 1, 20);
- hws[IMX8MM_SYS_PLL1_80M] = imx_clk_hw_fixed_factor("sys_pll1_80m", "sys_pll1_80m_cg", 1, 10);
- hws[IMX8MM_SYS_PLL1_100M] = imx_clk_hw_fixed_factor("sys_pll1_100m", "sys_pll1_100m_cg", 1, 8);
- hws[IMX8MM_SYS_PLL1_133M] = imx_clk_hw_fixed_factor("sys_pll1_133m", "sys_pll1_133m_cg", 1, 6);
- hws[IMX8MM_SYS_PLL1_160M] = imx_clk_hw_fixed_factor("sys_pll1_160m", "sys_pll1_160m_cg", 1, 5);
- hws[IMX8MM_SYS_PLL1_200M] = imx_clk_hw_fixed_factor("sys_pll1_200m", "sys_pll1_200m_cg", 1, 4);
- hws[IMX8MM_SYS_PLL1_266M] = imx_clk_hw_fixed_factor("sys_pll1_266m", "sys_pll1_266m_cg", 1, 3);
- hws[IMX8MM_SYS_PLL1_400M] = imx_clk_hw_fixed_factor("sys_pll1_400m", "sys_pll1_400m_cg", 1, 2);
+ hws[IMX8MM_SYS_PLL1_40M] = imx_clk_hw_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20);
+ hws[IMX8MM_SYS_PLL1_80M] = imx_clk_hw_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10);
+ hws[IMX8MM_SYS_PLL1_100M] = imx_clk_hw_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8);
+ hws[IMX8MM_SYS_PLL1_133M] = imx_clk_hw_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6);
+ hws[IMX8MM_SYS_PLL1_160M] = imx_clk_hw_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5);
+ hws[IMX8MM_SYS_PLL1_200M] = imx_clk_hw_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4);
+ hws[IMX8MM_SYS_PLL1_266M] = imx_clk_hw_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3);
+ hws[IMX8MM_SYS_PLL1_400M] = imx_clk_hw_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2);
hws[IMX8MM_SYS_PLL1_800M] = imx_clk_hw_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1);
/* SYS PLL2 fixed output */
- hws[IMX8MM_SYS_PLL2_50M_CG] = imx_clk_hw_gate("sys_pll2_50m_cg", "sys_pll2", base + 0x104, 27);
- hws[IMX8MM_SYS_PLL2_100M_CG] = imx_clk_hw_gate("sys_pll2_100m_cg", "sys_pll2", base + 0x104, 25);
- hws[IMX8MM_SYS_PLL2_125M_CG] = imx_clk_hw_gate("sys_pll2_125m_cg", "sys_pll2", base + 0x104, 23);
- hws[IMX8MM_SYS_PLL2_166M_CG] = imx_clk_hw_gate("sys_pll2_166m_cg", "sys_pll2", base + 0x104, 21);
- hws[IMX8MM_SYS_PLL2_200M_CG] = imx_clk_hw_gate("sys_pll2_200m_cg", "sys_pll2", base + 0x104, 19);
- hws[IMX8MM_SYS_PLL2_250M_CG] = imx_clk_hw_gate("sys_pll2_250m_cg", "sys_pll2", base + 0x104, 17);
- hws[IMX8MM_SYS_PLL2_333M_CG] = imx_clk_hw_gate("sys_pll2_333m_cg", "sys_pll2", base + 0x104, 15);
- hws[IMX8MM_SYS_PLL2_500M_CG] = imx_clk_hw_gate("sys_pll2_500m_cg", "sys_pll2", base + 0x104, 13);
hws[IMX8MM_SYS_PLL2_OUT] = imx_clk_hw_gate("sys_pll2_out", "sys_pll2", base + 0x104, 11);
- hws[IMX8MM_SYS_PLL2_50M] = imx_clk_hw_fixed_factor("sys_pll2_50m", "sys_pll2_50m_cg", 1, 20);
- hws[IMX8MM_SYS_PLL2_100M] = imx_clk_hw_fixed_factor("sys_pll2_100m", "sys_pll2_100m_cg", 1, 10);
- hws[IMX8MM_SYS_PLL2_125M] = imx_clk_hw_fixed_factor("sys_pll2_125m", "sys_pll2_125m_cg", 1, 8);
- hws[IMX8MM_SYS_PLL2_166M] = imx_clk_hw_fixed_factor("sys_pll2_166m", "sys_pll2_166m_cg", 1, 6);
- hws[IMX8MM_SYS_PLL2_200M] = imx_clk_hw_fixed_factor("sys_pll2_200m", "sys_pll2_200m_cg", 1, 5);
- hws[IMX8MM_SYS_PLL2_250M] = imx_clk_hw_fixed_factor("sys_pll2_250m", "sys_pll2_250m_cg", 1, 4);
- hws[IMX8MM_SYS_PLL2_333M] = imx_clk_hw_fixed_factor("sys_pll2_333m", "sys_pll2_333m_cg", 1, 3);
- hws[IMX8MM_SYS_PLL2_500M] = imx_clk_hw_fixed_factor("sys_pll2_500m", "sys_pll2_500m_cg", 1, 2);
+ hws[IMX8MM_SYS_PLL2_50M] = imx_clk_hw_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20);
+ hws[IMX8MM_SYS_PLL2_100M] = imx_clk_hw_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10);
+ hws[IMX8MM_SYS_PLL2_125M] = imx_clk_hw_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8);
+ hws[IMX8MM_SYS_PLL2_166M] = imx_clk_hw_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6);
+ hws[IMX8MM_SYS_PLL2_200M] = imx_clk_hw_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5);
+ hws[IMX8MM_SYS_PLL2_250M] = imx_clk_hw_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4);
+ hws[IMX8MM_SYS_PLL2_333M] = imx_clk_hw_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3);
+ hws[IMX8MM_SYS_PLL2_500M] = imx_clk_hw_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2);
hws[IMX8MM_SYS_PLL2_1000M] = imx_clk_hw_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1);
hws[IMX8MM_CLK_CLKOUT1_SEL] = imx_clk_hw_mux2("clkout1_sel", base + 0x128, 4, 4, clkout_sels, ARRAY_SIZE(clkout_sels));
@@ -449,7 +466,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
/* BUS */
hws[IMX8MM_CLK_MAIN_AXI] = imx8m_clk_hw_composite_bus_critical("main_axi", imx8mm_main_axi_sels, base + 0x8800);
hws[IMX8MM_CLK_ENET_AXI] = imx8m_clk_hw_composite_bus("enet_axi", imx8mm_enet_axi_sels, base + 0x8880);
- hws[IMX8MM_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite_bus_critical("nand_usdhc_bus", imx8mm_nand_usdhc_sels, base + 0x8900);
+ hws[IMX8MM_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite("nand_usdhc_bus", imx8mm_nand_usdhc_sels, base + 0x8900);
hws[IMX8MM_CLK_VPU_BUS] = imx8m_clk_hw_composite_bus("vpu_bus", imx8mm_vpu_bus_sels, base + 0x8980);
hws[IMX8MM_CLK_DISP_AXI] = imx8m_clk_hw_composite_bus("disp_axi", imx8mm_disp_axi_sels, base + 0x8a00);
hws[IMX8MM_CLK_DISP_APB] = imx8m_clk_hw_composite_bus("disp_apb", imx8mm_disp_apb_sels, base + 0x8a80);
@@ -577,7 +594,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
hws[IMX8MM_CLK_SAI5_IPG] = imx_clk_hw_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
hws[IMX8MM_CLK_SAI6_ROOT] = imx_clk_hw_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6);
hws[IMX8MM_CLK_SAI6_IPG] = imx_clk_hw_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
- hws[IMX8MM_CLK_SNVS_ROOT] = imx_clk_hw_gate4("snvs_root_clk", "ipg_root", base + 0x4470, 0);
+ hws[IMX8MM_CLK_SNVS_ROOT] = imx_clk_hw_gate2_flags("snvs_root_clk", "ipg_root", base + 0x4470, 0, CLK_IS_CRITICAL);
hws[IMX8MM_CLK_UART1_ROOT] = imx_clk_hw_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
hws[IMX8MM_CLK_UART2_ROOT] = imx_clk_hw_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
hws[IMX8MM_CLK_UART3_ROOT] = imx_clk_hw_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
@@ -627,6 +644,12 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
goto unregister_hws;
}
+ imx_clk_init_on(np, hws);
+
+ clk_set_parent(hws[IMX8MM_CLK_CSI1_CORE]->clk, hws[IMX8MM_SYS_PLL2_1000M]->clk);
+ clk_set_parent(hws[IMX8MM_CLK_CSI1_PHY_REF]->clk, hws[IMX8MM_SYS_PLL2_1000M]->clk);
+ clk_set_parent(hws[IMX8MM_CLK_CSI1_ESC]->clk, hws[IMX8MM_SYS_PLL1_800M]->clk);
+
imx_register_uart_clocks(4);
return 0;
@@ -657,6 +680,83 @@ static struct platform_driver imx8mm_clk_driver = {
};
module_platform_driver(imx8mm_clk_driver);
+/*
+ * Debugfs interface for audio PLL K divider change dynamically.
+ * Monitor control for the Audio PLL K-Divider
+ */
+#ifdef CONFIG_DEBUG_FS
+
+#define KDIV_MASK GENMASK(15, 0)
+#define MDIV_SHIFT 12
+#define MDIV_MASK GENMASK(21, 12)
+#define PDIV_SHIFT 4
+#define PDIV_MASK GENMASK(9, 4)
+#define SDIV_SHIFT 0
+#define SDIV_MASK GENMASK(2, 0)
+
+static int pll_delta_k_set(void *data, u64 val)
+{
+ struct clk_hw *hw;
+ short int delta_k;
+
+ hw = data;
+ delta_k = (short int) (val & KDIV_MASK);
+
+ clk_set_delta_k(hw, val);
+
+ pr_debug("the delta k is %d\n", delta_k);
+ return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(delta_k_fops, NULL, pll_delta_k_set, "%lld\n");
+
+static int pll_setting_show(struct seq_file *s, void *data)
+{
+ struct clk_hw *hw;
+ u32 pll_div_ctrl0, pll_div_ctrl1;
+ u32 mdiv, pdiv, sdiv, kdiv;
+
+ hw = s->private;;
+
+ clk_get_pll_setting(hw, &pll_div_ctrl0, &pll_div_ctrl1);
+ mdiv = (pll_div_ctrl0 & MDIV_MASK) >> MDIV_SHIFT;
+ pdiv = (pll_div_ctrl0 & PDIV_MASK) >> PDIV_SHIFT;
+ sdiv = (pll_div_ctrl0 & SDIV_MASK) >> SDIV_SHIFT;
+ kdiv = (pll_div_ctrl1 & KDIV_MASK);
+
+ seq_printf(s, "Mdiv: 0x%x; Pdiv: 0x%x; Sdiv: 0x%x; Kdiv: 0x%x\n",
+ mdiv, pdiv, sdiv, kdiv);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(pll_setting);
+
+#ifndef MODULE
+static int __init pll_debug_init(void)
+{
+ struct dentry *root, *audio_pll1, *audio_pll2;
+
+ if (of_machine_is_compatible("fsl,imx8mm") && hws) {
+ /* create a root dir for audio pll monitor */
+ root = debugfs_create_dir("audio_pll_monitor", NULL);
+ audio_pll1 = debugfs_create_dir("audio_pll1", root);
+ audio_pll2 = debugfs_create_dir("audio_pll2", root);
+
+ debugfs_create_file_unsafe("delta_k", 0444, audio_pll1,
+ hws[IMX8MM_AUDIO_PLL1], &delta_k_fops);
+ debugfs_create_file("pll_parameter", 0x444, audio_pll1,
+ hws[IMX8MM_AUDIO_PLL1], &pll_setting_fops);
+ debugfs_create_file_unsafe("delta_k", 0444, audio_pll2,
+ hws[IMX8MM_AUDIO_PLL2], &delta_k_fops);
+ debugfs_create_file("pll_parameter", 0x444, audio_pll2,
+ hws[IMX8MM_AUDIO_PLL2], &pll_setting_fops);
+ }
+
+ return 0;
+}
+late_initcall(pll_debug_init);
+#endif /* MODULE */
+#endif /* CONFIG_DEBUG_FS */
+
MODULE_AUTHOR("Bai Ping <ping.bai@nxp.com>");
MODULE_DESCRIPTION("NXP i.MX8MM clock driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c
index 021355a24708..7b45de388351 100644
--- a/drivers/clk/imx/clk-imx8mn.c
+++ b/drivers/clk/imx/clk-imx8mn.c
@@ -4,6 +4,7 @@
*/
#include <dt-bindings/clock/imx8mn-clock.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
@@ -12,6 +13,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <soc/imx/soc.h>
#include "clk.h"
@@ -292,6 +294,34 @@ static const char * const clkout_sels[] = {"audio_pll1_out", "audio_pll2_out", "
static struct clk_hw_onecell_data *clk_hw_data;
static struct clk_hw **hws;
+static int imx_clk_init_on(struct device_node *np,
+ struct clk_hw * const clks[])
+{
+ u32 *array;
+ int i, ret, elems;
+
+ elems = of_property_count_u32_elems(np, "init-on-array");
+ if (elems < 0)
+ return elems;
+ array = kcalloc(elems, sizeof(elems), GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(np, "init-on-array", array, elems);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < elems; i++) {
+ ret = clk_prepare_enable(clks[array[i]]->clk);
+ if (ret)
+ pr_err("clk_prepare_enable failed %d\n", array[i]);
+ }
+
+ kfree(array);
+
+ return 0;
+}
+
static int imx8mn_clocks_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -299,6 +329,8 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
void __iomem *base;
int ret;
+ check_m4_enabled();
+
clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
IMX8MN_CLK_END), GFP_KERNEL);
if (WARN_ON(!clk_hw_data))
@@ -364,45 +396,29 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
hws[IMX8MN_SYS_PLL3_OUT] = imx_clk_hw_gate("sys_pll3_out", "sys_pll3_bypass", base + 0x114, 11);
/* SYS PLL1 fixed output */
- hws[IMX8MN_SYS_PLL1_40M_CG] = imx_clk_hw_gate("sys_pll1_40m_cg", "sys_pll1", base + 0x94, 27);
- hws[IMX8MN_SYS_PLL1_80M_CG] = imx_clk_hw_gate("sys_pll1_80m_cg", "sys_pll1", base + 0x94, 25);
- hws[IMX8MN_SYS_PLL1_100M_CG] = imx_clk_hw_gate("sys_pll1_100m_cg", "sys_pll1", base + 0x94, 23);
- hws[IMX8MN_SYS_PLL1_133M_CG] = imx_clk_hw_gate("sys_pll1_133m_cg", "sys_pll1", base + 0x94, 21);
- hws[IMX8MN_SYS_PLL1_160M_CG] = imx_clk_hw_gate("sys_pll1_160m_cg", "sys_pll1", base + 0x94, 19);
- hws[IMX8MN_SYS_PLL1_200M_CG] = imx_clk_hw_gate("sys_pll1_200m_cg", "sys_pll1", base + 0x94, 17);
- hws[IMX8MN_SYS_PLL1_266M_CG] = imx_clk_hw_gate("sys_pll1_266m_cg", "sys_pll1", base + 0x94, 15);
- hws[IMX8MN_SYS_PLL1_400M_CG] = imx_clk_hw_gate("sys_pll1_400m_cg", "sys_pll1", base + 0x94, 13);
hws[IMX8MN_SYS_PLL1_OUT] = imx_clk_hw_gate("sys_pll1_out", "sys_pll1", base + 0x94, 11);
- hws[IMX8MN_SYS_PLL1_40M] = imx_clk_hw_fixed_factor("sys_pll1_40m", "sys_pll1_40m_cg", 1, 20);
- hws[IMX8MN_SYS_PLL1_80M] = imx_clk_hw_fixed_factor("sys_pll1_80m", "sys_pll1_80m_cg", 1, 10);
- hws[IMX8MN_SYS_PLL1_100M] = imx_clk_hw_fixed_factor("sys_pll1_100m", "sys_pll1_100m_cg", 1, 8);
- hws[IMX8MN_SYS_PLL1_133M] = imx_clk_hw_fixed_factor("sys_pll1_133m", "sys_pll1_133m_cg", 1, 6);
- hws[IMX8MN_SYS_PLL1_160M] = imx_clk_hw_fixed_factor("sys_pll1_160m", "sys_pll1_160m_cg", 1, 5);
- hws[IMX8MN_SYS_PLL1_200M] = imx_clk_hw_fixed_factor("sys_pll1_200m", "sys_pll1_200m_cg", 1, 4);
- hws[IMX8MN_SYS_PLL1_266M] = imx_clk_hw_fixed_factor("sys_pll1_266m", "sys_pll1_266m_cg", 1, 3);
- hws[IMX8MN_SYS_PLL1_400M] = imx_clk_hw_fixed_factor("sys_pll1_400m", "sys_pll1_400m_cg", 1, 2);
+ hws[IMX8MN_SYS_PLL1_40M] = imx_clk_hw_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20);
+ hws[IMX8MN_SYS_PLL1_80M] = imx_clk_hw_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10);
+ hws[IMX8MN_SYS_PLL1_100M] = imx_clk_hw_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8);
+ hws[IMX8MN_SYS_PLL1_133M] = imx_clk_hw_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6);
+ hws[IMX8MN_SYS_PLL1_160M] = imx_clk_hw_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5);
+ hws[IMX8MN_SYS_PLL1_200M] = imx_clk_hw_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4);
+ hws[IMX8MN_SYS_PLL1_266M] = imx_clk_hw_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3);
+ hws[IMX8MN_SYS_PLL1_400M] = imx_clk_hw_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2);
hws[IMX8MN_SYS_PLL1_800M] = imx_clk_hw_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1);
/* SYS PLL2 fixed output */
- hws[IMX8MN_SYS_PLL2_50M_CG] = imx_clk_hw_gate("sys_pll2_50m_cg", "sys_pll2", base + 0x104, 27);
- hws[IMX8MN_SYS_PLL2_100M_CG] = imx_clk_hw_gate("sys_pll2_100m_cg", "sys_pll2", base + 0x104, 25);
- hws[IMX8MN_SYS_PLL2_125M_CG] = imx_clk_hw_gate("sys_pll2_125m_cg", "sys_pll2", base + 0x104, 23);
- hws[IMX8MN_SYS_PLL2_166M_CG] = imx_clk_hw_gate("sys_pll2_166m_cg", "sys_pll2", base + 0x104, 21);
- hws[IMX8MN_SYS_PLL2_200M_CG] = imx_clk_hw_gate("sys_pll2_200m_cg", "sys_pll2", base + 0x104, 19);
- hws[IMX8MN_SYS_PLL2_250M_CG] = imx_clk_hw_gate("sys_pll2_250m_cg", "sys_pll2", base + 0x104, 17);
- hws[IMX8MN_SYS_PLL2_333M_CG] = imx_clk_hw_gate("sys_pll2_333m_cg", "sys_pll2", base + 0x104, 15);
- hws[IMX8MN_SYS_PLL2_500M_CG] = imx_clk_hw_gate("sys_pll2_500m_cg", "sys_pll2", base + 0x104, 13);
hws[IMX8MN_SYS_PLL2_OUT] = imx_clk_hw_gate("sys_pll2_out", "sys_pll2", base + 0x104, 11);
- hws[IMX8MN_SYS_PLL2_50M] = imx_clk_hw_fixed_factor("sys_pll2_50m", "sys_pll2_50m_cg", 1, 20);
- hws[IMX8MN_SYS_PLL2_100M] = imx_clk_hw_fixed_factor("sys_pll2_100m", "sys_pll2_100m_cg", 1, 10);
- hws[IMX8MN_SYS_PLL2_125M] = imx_clk_hw_fixed_factor("sys_pll2_125m", "sys_pll2_125m_cg", 1, 8);
- hws[IMX8MN_SYS_PLL2_166M] = imx_clk_hw_fixed_factor("sys_pll2_166m", "sys_pll2_166m_cg", 1, 6);
- hws[IMX8MN_SYS_PLL2_200M] = imx_clk_hw_fixed_factor("sys_pll2_200m", "sys_pll2_200m_cg", 1, 5);
- hws[IMX8MN_SYS_PLL2_250M] = imx_clk_hw_fixed_factor("sys_pll2_250m", "sys_pll2_250m_cg", 1, 4);
- hws[IMX8MN_SYS_PLL2_333M] = imx_clk_hw_fixed_factor("sys_pll2_333m", "sys_pll2_333m_cg", 1, 3);
- hws[IMX8MN_SYS_PLL2_500M] = imx_clk_hw_fixed_factor("sys_pll2_500m", "sys_pll2_500m_cg", 1, 2);
+ hws[IMX8MN_SYS_PLL2_50M] = imx_clk_hw_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20);
+ hws[IMX8MN_SYS_PLL2_100M] = imx_clk_hw_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10);
+ hws[IMX8MN_SYS_PLL2_125M] = imx_clk_hw_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8);
+ hws[IMX8MN_SYS_PLL2_166M] = imx_clk_hw_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6);
+ hws[IMX8MN_SYS_PLL2_200M] = imx_clk_hw_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5);
+ hws[IMX8MN_SYS_PLL2_250M] = imx_clk_hw_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4);
+ hws[IMX8MN_SYS_PLL2_333M] = imx_clk_hw_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3);
+ hws[IMX8MN_SYS_PLL2_500M] = imx_clk_hw_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2);
hws[IMX8MN_SYS_PLL2_1000M] = imx_clk_hw_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1);
hws[IMX8MN_CLK_CLKOUT1_SEL] = imx_clk_hw_mux2("clkout1_sel", base + 0x128, 4, 4, clkout_sels, ARRAY_SIZE(clkout_sels));
@@ -540,7 +556,7 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
hws[IMX8MN_CLK_SAI5_IPG] = imx_clk_hw_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
hws[IMX8MN_CLK_SAI6_ROOT] = imx_clk_hw_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6);
hws[IMX8MN_CLK_SAI6_IPG] = imx_clk_hw_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
- hws[IMX8MN_CLK_SNVS_ROOT] = imx_clk_hw_gate4("snvs_root_clk", "ipg_root", base + 0x4470, 0);
+ hws[IMX8MN_CLK_SNVS_ROOT] = imx_clk_hw_gate2_flags("snvs_root_clk", "ipg_root", base + 0x4470, 0, CLK_IS_CRITICAL);
hws[IMX8MN_CLK_UART1_ROOT] = imx_clk_hw_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
hws[IMX8MN_CLK_UART2_ROOT] = imx_clk_hw_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
hws[IMX8MN_CLK_UART3_ROOT] = imx_clk_hw_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
@@ -566,6 +582,7 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
hws[IMX8MN_CLK_SDMA2_ROOT] = imx_clk_hw_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0);
hws[IMX8MN_CLK_SDMA3_ROOT] = imx_clk_hw_gate4("sdma3_clk", "ipg_audio_root", base + 0x45f0, 0);
hws[IMX8MN_CLK_SAI7_ROOT] = imx_clk_hw_gate2_shared2("sai7_root_clk", "sai7", base + 0x4650, 0, &share_count_sai7);
+ hws[IMX8MN_CLK_SAI7_IPG] = imx_clk_hw_gate2_shared2("sai7_ipg_clk", "ipg_audio_root", base + 0x4650, 0, &share_count_sai7);
hws[IMX8MN_CLK_DRAM_ALT_ROOT] = imx_clk_hw_fixed_factor("dram_alt_root", "dram_alt", 1, 4);
@@ -583,6 +600,12 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
goto unregister_hws;
}
+ imx_clk_init_on(np, hws);
+
+ clk_set_parent(hws[IMX8MN_CLK_AUDIO_AHB]->clk, hws[IMX8MN_SYS_PLL1_800M]->clk);
+ clk_set_rate(hws[IMX8MN_CLK_AUDIO_AHB]->clk, 400000000);
+ clk_set_rate(hws[IMX8MN_CLK_IPG_AUDIO_ROOT]->clk, 400000000);
+
imx_register_uart_clocks(4);
return 0;
diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c
index 12837304545d..aa80334196ff 100644
--- a/drivers/clk/imx/clk-imx8mp.c
+++ b/drivers/clk/imx/clk-imx8mp.c
@@ -4,7 +4,10 @@
*/
#include <dt-bindings/clock/imx8mp-clock.h>
+#include <dt-bindings/reset/imx8mp-reset.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/debugfs.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -12,11 +15,289 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <soc/imx/soc.h>
#include "clk.h"
+#include "clk-blk-ctrl.h"
+
+#define IMX_AUDIO_BLK_CTRL_CLKEN0 0x0
+#define IMX_AUDIO_BLK_CTRL_CLKEN1 0x4
+#define IMX_AUDIO_BLK_CTRL_EARC 0x200
+#define IMX_AUDIO_BLK_CTRL_SAI1_MCLK_SEL 0x300
+#define IMX_AUDIO_BLK_CTRL_SAI2_MCLK_SEL 0x304
+#define IMX_AUDIO_BLK_CTRL_SAI3_MCLK_SEL 0x308
+#define IMX_AUDIO_BLK_CTRL_SAI5_MCLK_SEL 0x30C
+#define IMX_AUDIO_BLK_CTRL_SAI6_MCLK_SEL 0x310
+#define IMX_AUDIO_BLK_CTRL_SAI7_MCLK_SEL 0x314
+#define IMX_AUDIO_BLK_CTRL_PDM_CLK 0x318
+#define IMX_AUDIO_BLK_CTRL_SAI_PLL_GNRL_CTL 0x400
+#define IMX_AUDIO_BLK_CTRL_SAI_PLL_FDIVL_CTL0 0x404
+#define IMX_AUDIO_BLK_CTRL_SAI_PLL_FDIVL_CTL1 0x408
+#define IMX_AUDIO_BLK_CTRL_SAI_PLL_SSCG_CTL 0x40C
+#define IMX_AUDIO_BLK_CTRL_SAI_PLL_MNIT_CTL 0x410
+#define IMX_AUDIO_BLK_CTRL_IPG_LP_CTRL 0x504
+
+#define IMX_MEDIA_BLK_CTRL_SFT_RSTN 0x0
+#define IMX_MEDIA_BLK_CTRL_CLK_EN 0x4
static u32 share_count_nand;
static u32 share_count_media;
+static u32 share_count_audio;
+
+static int shared_count_pdm;
+
+/* descending order */
+static const struct imx_pll14xx_rate_table imx_blk_ctrl_sai_pll_tbl[] = {
+ PLL_1443X_RATE(245760000U, 328, 4, 3, 0xae15),
+ PLL_1443X_RATE(225792000U, 226, 3, 3, 0xcac1),
+ PLL_1443X_RATE(122880000U, 328, 4, 4, 0xae15),
+ PLL_1443X_RATE(112896000U, 226, 3, 4, 0xcac1),
+ PLL_1443X_RATE(61440000U, 328, 4, 5, 0xae15),
+ PLL_1443X_RATE(56448000U, 226, 3, 5, 0xcac1),
+ PLL_1443X_RATE(49152000U, 393, 3, 6, 0x374c),
+ PLL_1443X_RATE(45158400U, 241, 2, 6, 0xd845),
+ PLL_1443X_RATE(40960000U, 109, 1, 6, 0x3a07),
+};
+
+static const struct imx_pll14xx_clk imx_blk_ctrl_sai_pll = {
+ .type = PLL_1443X,
+ .rate_table = imx_blk_ctrl_sai_pll_tbl,
+ .rate_count = ARRAY_SIZE(imx_blk_ctrl_sai_pll_tbl),
+};
+
+static const char *imx_sai_mclk2_sels[] = {"sai1_root", "sai2_root", "sai3_root", "dummy",
+ "sai5_root", "sai6_root", "sai7_root", "sai1_mclk",
+ "sai2_mclk", "sai3_mclk", "dummy",
+ "sai5_mclk", "sai6_mclk", "sai7_mclk", "spdif1_ext_clk"};
+static const char *imx_sai1_mclk1_sels[] = {"sai1_root", "sai1_mclk", };
+static const char *imx_sai2_mclk1_sels[] = {"sai2_root", "sai2_mclk", };
+static const char *imx_sai3_mclk1_sels[] = {"sai3_root", "sai3_mclk", };
+static const char *imx_sai5_mclk1_sels[] = {"sai5_root", "sai5_mclk", };
+static const char *imx_sai6_mclk1_sels[] = {"sai6_root", "sai6_mclk", };
+static const char *imx_sai7_mclk1_sels[] = {"sai7_root", "sai7_mclk", };
+static const char *imx_pdm_sels[] = {"pdm_root", "sai_pll_div2", "dummy", "dummy" };
+static const char *imx_sai_pll_ref_sels[] = {"osc_24m", "dummy", "dummy", "dummy", };
+static const char *imx_sai_pll_bypass_sels[] = {"sai_pll", "sai_pll_ref_sel", };
+
+static const char *imx_hdmi_phy_clks_sels[] = { "hdmi_glb_24m", "dummy",};
+static const char *imx_lcdif_clks_sels[] = { "dummy", "hdmi_glb_pix", };
+static const char *imx_hdmi_pipe_clks_sels[] = {"dummy","hdmi_glb_pix", };
+
+static struct imx_blk_ctrl_hw imx8mp_hdmi_blk_ctrl_hws[] = {
+ /* clocks */
+ IMX_BLK_CTRL_CLK_GATE("hdmi_glb_apb", IMX8MP_CLK_HDMI_BLK_CTRL_GLOBAL_APB_CLK, 0x40, 0, "hdmi_apb"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_glb_b", IMX8MP_CLK_HDMI_BLK_CTRL_GLOBAL_B_CLK, 0x40, 1, "hdmi_axi"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_glb_ref_266m", IMX8MP_CLK_HDMI_BLK_CTRL_GLOBAL_REF266M_CLK, 0x40, 2, "hdmi_ref_266m"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_glb_24m", IMX8MP_CLK_HDMI_BLK_CTRL_GLOBAL_XTAL24M_CLK, 0x40, 4, "hdmi_24m"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_glb_32k", IMX8MP_CLK_HDMI_BLK_CTRL_GLOBAL_XTAL32K_CLK, 0x40, 5, "osc_32k"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_glb_pix", IMX8MP_CLK_HDMI_BLK_CTRL_GLOBAL_TX_PIX_CLK, 0x40, 7, "hdmi_phy"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_irq_steer", IMX8MP_CLK_HDMI_BLK_CTRL_IRQS_STEER_CLK, 0x40, 9, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_noc", IMX8MP_CLK_HDMI_BLK_CTRL_NOC_HDMI_CLK, 0x40, 10, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("hdcp_noc", IMX8MP_CLK_HDMI_BLK_CTRL_NOC_HDCP_CLK, 0x40, 11, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("lcdif3_apb", IMX8MP_CLK_HDMI_BLK_CTRL_LCDIF_APB_CLK, 0x40, 16, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("lcdif3_b", IMX8MP_CLK_HDMI_BLK_CTRL_LCDIF_B_CLK, 0x40, 17, "hdmi_glb_b"),
+ IMX_BLK_CTRL_CLK_GATE("lcdif3_pdi", IMX8MP_CLK_HDMI_BLK_CTRL_LCDIF_PDI_CLK, 0x40, 18, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("lcdif3_pxl", IMX8MP_CLK_HDMI_BLK_CTRL_LCDIF_PIX_CLK, 0x40, 19, "hdmi_glb_pix"),
+ IMX_BLK_CTRL_CLK_GATE("lcdif3_spu", IMX8MP_CLK_HDMI_BLK_CTRL_LCDIF_SPU_CLK, 0x40, 20, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_fdcc_ref", IMX8MP_CLK_HDMI_BLK_CTRL_FDCC_REF_CLK, 0x50, 2, "hdmi_fdcc_tst"),
+ IMX_BLK_CTRL_CLK_GATE("hrv_mwr_apb", IMX8MP_CLK_HDMI_BLK_CTRL_HRV_MWR_APB_CLK, 0x50, 3, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("hrv_mwr_b", IMX8MP_CLK_HDMI_BLK_CTRL_HRV_MWR_B_CLK, 0x50, 4, "hdmi_glb_axi"),
+ IMX_BLK_CTRL_CLK_GATE("hrv_mwr_cea", IMX8MP_CLK_HDMI_BLK_CTRL_HRV_MWR_CEA_CLK, 0x50, 5, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("vsfd_cea", IMX8MP_CLK_HDMI_BLK_CTRL_VSFD_CEA_CLK, 0x50, 6, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_tx_hpi", IMX8MP_CLK_HDMI_BLK_CTRL_TX_HPI_CLK, 0x50, 13, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_tx_apb", IMX8MP_CLK_HDMI_BLK_CTRL_TX_APB_CLK, 0x50, 14, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_cec", IMX8MP_CLK_HDMI_BLK_CTRL_TX_CEC_CLK, 0x50, 15, "hdmi_glb_32k"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_esm", IMX8MP_CLK_HDMI_BLK_CTRL_TX_ESM_CLK, 0x50, 16, "hdmi_glb_ref_266m"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_tx_gpa", IMX8MP_CLK_HDMI_BLK_CTRL_TX_GPA_CLK, 0x50, 17, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_tx_pix", IMX8MP_CLK_HDMI_BLK_CTRL_TX_PIXEL_CLK, 0x50, 18, "hdmi_glb_pix"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_tx_sfr", IMX8MP_CLK_HDMI_BLK_CTRL_TX_SFR_CLK, 0x50, 19, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_tx_skp", IMX8MP_CLK_HDMI_BLK_CTRL_TX_SKP_CLK, 0x50, 20, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_tx_prep", IMX8MP_CLK_HDMI_BLK_CTRL_TX_PREP_CLK, 0x50, 21, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_phy_apb", IMX8MP_CLK_HDMI_BLK_CTRL_TX_PHY_APB_CLK, 0x50, 22, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_phy_int", IMX8MP_CLK_HDMI_BLK_CTRL_TX_PHY_INT_CLK, 0x50, 24, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_sec_mem", IMX8MP_CLK_HDMI_BLK_CTRL_TX_SEC_MEM_CLK, 0x50, 25, "hdmi_glb_ref_266m"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_trng_skp", IMX8MP_CLK_HDMI_BLK_CTRL_TX_TRNG_SKP_CLK, 0x50, 27, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_vid_pix", IMX8MP_CLK_HDMI_BLK_CTRL_TX_VID_LINK_PIX_CLK, 0x50, 28, "hdmi_glb_pix"),
+ IMX_BLK_CTRL_CLK_GATE("hdmi_trng_apb", IMX8MP_CLK_HDMI_BLK_CTRL_TX_TRNG_APB_CLK, 0x50, 30, "hdmi_glb_apb"),
+ IMX_BLK_CTRL_CLK_MUX("hdmi_phy_sel", IMX8MP_CLK_HDMI_BLK_CTRL_HTXPHY_CLK_SEL, 0x50, 10, 1, imx_hdmi_phy_clks_sels),
+ IMX_BLK_CTRL_CLK_MUX("lcdif_clk_sel", IMX8MP_CLK_HDMI_BLK_CTRL_LCDIF_CLK_SEL, 0x50, 11, 1, imx_lcdif_clks_sels),
+ IMX_BLK_CTRL_CLK_MUX("hdmi_pipe_sel", IMX8MP_CLK_HDMI_BLK_CTRL_TX_PIPE_CLK_SEL, 0x50, 12, 1, imx_hdmi_pipe_clks_sels),
+
+ /* resets */
+ IMX_BLK_CTRL_RESET_MASK(IMX8MP_HDMI_BLK_CTRL_HDMI_TX_RESET, 0x20, 6, 0x33),
+ IMX_BLK_CTRL_RESET(IMX8MP_HDMI_BLK_CTRL_HDMI_PHY_RESET, 0x20, 12),
+ IMX_BLK_CTRL_RESET(IMX8MP_HDMI_BLK_CTRL_HDMI_PAI_RESET, 0x20, 18),
+ IMX_BLK_CTRL_RESET(IMX8MP_HDMI_BLK_CTRL_HDMI_PVI_RESET, 0x20, 22),
+ IMX_BLK_CTRL_RESET(IMX8MP_HDMI_BLK_CTRL_HDMI_TRNG_RESET, 0x20, 20),
+ IMX_BLK_CTRL_RESET(IMX8MP_HDMI_BLK_CTRL_IRQ_STEER_RESET, 0x20, 16),
+ IMX_BLK_CTRL_RESET(IMX8MP_HDMI_BLK_CTRL_HDMI_HDCP_RESET, 0x20, 13),
+ IMX_BLK_CTRL_RESET_MASK(IMX8MP_HDMI_BLK_CTRL_LCDIF_RESET, 0x20, 4, 0x3),
+};
+
+static struct imx_blk_ctrl_hw imx8mp_media_blk_ctrl_hws[] = {
+ /* clocks */
+ IMX_BLK_CTRL_CLK_GATE("mipi_dsi_pclk", IMX8MP_CLK_MEDIA_BLK_CTRL_MIPI_DSI_PCLK, 0x4, 0, "media_apb_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("mipi_dsi_clkref", IMX8MP_CLK_MEDIA_BLK_CTRL_MIPI_DSI_CLKREF, 0x4, 1, "media_mipi_phy1_ref"),
+ IMX_BLK_CTRL_CLK_GATE("mipi_csi_pclk", IMX8MP_CLK_MEDIA_BLK_CTRL_MIPI_CSI_PCLK, 0x4, 2, "media_apb_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("mipi_csi_aclk", IMX8MP_CLK_MEDIA_BLK_CTRL_MIPI_CSI_ACLK, 0x4, 3, "media_cam1_pix_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("lcdif_pixel_clk", IMX8MP_CLK_MEDIA_BLK_CTRL_LCDIF_PIXEL, 0x4, 4, "media_disp1_pix_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("lcdif_apb_clk", IMX8MP_CLK_MEDIA_BLK_CTRL_LCDIF_APB, 0x4, 5, "media_apb_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("isi_proc_clk", IMX8MP_CLK_MEDIA_BLK_CTRL_ISI_PROC, 0x4, 6, "media_axi_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("isi_apb_clk", IMX8MP_CLK_MEDIA_BLK_CTRL_ISI_APB, 0x4, 7, "media_apb_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("mipi_csi2_pclk", IMX8MP_CLK_MEDIA_BLK_CTRL_MIPI_CSI2_PCLK, 0x4, 9, "media_apb_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("mipi_csi2_aclk", IMX8MP_CLK_MEDIA_BLK_CTRL_MIPI_CSI2_ACLK, 0x4, 10, "media_cam2_pix_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("lcdif2_pixel_clk", IMX8MP_CLK_MEDIA_BLK_CTRL_LCDIF2_PIXEL, 0x4, 11, "media_disp2_pix_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("lcdif2_apb_clk", IMX8MP_CLK_MEDIA_BLK_CTRL_LCDIF2_APB, 0x4, 12, "media_apb_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("isp_cor_clk", IMX8MP_CLK_MEDIA_BLK_CTRL_ISP_COR, 0x4, 16, "media_isp_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("isp_axi_clk", IMX8MP_CLK_MEDIA_BLK_CTRL_ISP_AXI, 0x4, 17, "media_axi_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("isp_ahb_clk", IMX8MP_CLK_MEDIA_BLK_CTRL_ISP_AHB, 0x4, 18, "media_apb_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("dwe_cor_clk", IMX8MP_CLK_MEDIA_BLK_CTRL_DWE_COR, 0x4, 19, "media_axi_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("dwe_axi_clk", IMX8MP_CLK_MEDIA_BLK_CTRL_DWE_AXI, 0x4, 20, "media_axi_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("dwe_ahb_clk", IMX8MP_CLK_MEDIA_BLK_CTRL_DWE_AHB, 0x4, 21, "media_apb_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("mipi_dsi2_clk", IMX8MP_CLK_MEDIA_BLK_CTRL_MIPI_DSI2, 0x4, 22, "media_mipi_phy1_ref"),
+ IMX_BLK_CTRL_CLK_GATE("lcdif_axi_clk", IMX8MP_CLK_MEDIA_BLK_CTRL_LCDIF_AXI, 0x4, 23, "media_axi_root_clk"),
+ IMX_BLK_CTRL_CLK_GATE("lcdif2_axi_clk", IMX8MP_CLK_MEDIA_BLK_CTRL_LCDIF2_AXI, 0x4, 24, "media_axi_root_clk"),
+
+ /* resets */
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_MIPI_DSI_PCLK, 0, 0),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_MIPI_DSI_CLKREF, 0, 1),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_MIPI_CSI_PCLK, 0, 2),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_MIPI_CSI_ACLK, 0, 3),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_LCDIF_PIXEL, 0, 4),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_LCDIF_APB, 0, 5),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_ISI_PROC, 0, 6),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_ISI_APB, 0, 7),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_BUS_BLK, 0, 8),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_MIPI_CSI2_PCLK, 0, 9),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_MIPI_CSI2_ACLK, 0, 10),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_LCDIF2_PIXEL, 0, 11),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_LCDIF2_APB, 0, 12),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_ISP1_COR, 0, 13),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_ISP1_AXI, 0, 14),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_ISP1_AHB, 0, 15),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_ISP0_COR, 0, 16),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_ISP0_AXI, 0, 17),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_ISP0_AHB, 0, 18),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_DWE_COR, 0, 19),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_DWE_AXI, 0, 20),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_DWE_AHB, 0, 21),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_MIPI_DSI2, 0, 22),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_LCDIF_AXI, 0, 23),
+ IMX_BLK_CTRL_RESET(IMX8MP_MEDIA_BLK_CTRL_RESET_LCDIF2_AXI, 0, 24)
+};
+
+static struct imx_blk_ctrl_hw imx8mp_audio_blk_ctrl_hws[] = {
+ /* clocks */
+ IMX_BLK_CTRL_CLK_MUX("sai_pll_ref_sel", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI_PLL_REF_SEL, 0x400, 0, 2, imx_sai_pll_ref_sels),
+ IMX_BLK_CTRL_CLK_PLL14XX("sai_pll", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI_PLL, 0x400, "sai_pll_ref_sel", &imx_blk_ctrl_sai_pll),
+ IMX_BLK_CTRL_CLK_MUX_FLAGS("sai_pll_bypass", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI_PLL_BYPASS, 0x400, 4, 1, imx_sai_pll_bypass_sels, CLK_SET_RATE_PARENT),
+ IMX_BLK_CTRL_CLK_GATE("sai_pll_out", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI_PLL_OUT, 0x400, 13, "sai_pll_bypass"),
+ IMX_BLK_CTRL_CLK_MUX_FLAGS("sai1_mclk1_sel", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI1_MCLK1_SEL, 0x300, 0, 1, imx_sai1_mclk1_sels, CLK_SET_RATE_PARENT),
+ IMX_BLK_CTRL_CLK_MUX("sai1_mclk2_sel", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI1_MCLK2_SEL, 0x300, 1, 4, imx_sai_mclk2_sels),
+ IMX_BLK_CTRL_CLK_MUX_FLAGS("sai2_mclk1_sel", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI2_MCLK1_SEL, 0x304, 0, 1, imx_sai2_mclk1_sels, CLK_SET_RATE_PARENT),
+ IMX_BLK_CTRL_CLK_MUX("sai2_mclk2_sel", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI2_MCLK2_SEL, 0x304, 1, 4, imx_sai_mclk2_sels),
+ IMX_BLK_CTRL_CLK_MUX_FLAGS("sai3_mclk1_sel", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_MCLK1_SEL, 0x308, 0, 1, imx_sai3_mclk1_sels, CLK_SET_RATE_PARENT),
+ IMX_BLK_CTRL_CLK_MUX("sai3_mclk2_sel", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_MCLK2_SEL, 0x308, 1, 4, imx_sai_mclk2_sels),
+ IMX_BLK_CTRL_CLK_MUX("sai5_mclk1_sel", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI5_MCLK1_SEL, 0x30C, 0, 1, imx_sai5_mclk1_sels),
+ IMX_BLK_CTRL_CLK_MUX("sai5_mclk2_sel", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI5_MCLK2_SEL, 0x30C, 1, 4, imx_sai_mclk2_sels),
+ IMX_BLK_CTRL_CLK_MUX("sai6_mclk1_sel", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI6_MCLK1_SEL, 0x310, 0, 1, imx_sai6_mclk1_sels),
+ IMX_BLK_CTRL_CLK_MUX("sai6_mclk2_sel", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI6_MCLK2_SEL, 0x310, 1, 4, imx_sai_mclk2_sels),
+ IMX_BLK_CTRL_CLK_MUX("sai7_mclk1_sel", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI7_MCLK1_SEL, 0x314, 0, 1, imx_sai7_mclk1_sels),
+ IMX_BLK_CTRL_CLK_MUX("sai7_mclk2_sel", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI7_MCLK2_SEL, 0x314, 1, 4, imx_sai_mclk2_sels),
+ IMX_BLK_CTRL_CLK_MUX_FLAGS("pdm_sel", IMX8MP_CLK_AUDIO_BLK_CTRL_PDM_SEL, 0x318, 0, 2, imx_pdm_sels, CLK_SET_RATE_PARENT),
+ IMX_BLK_CTRL_CLK_GATE("sai1_ipg_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI1_IPG, 0, 0, "audio_ahb_root"),
+ IMX_BLK_CTRL_CLK_GATE("sai1_mclk1_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI1_MCLK1, 0, 1, "sai1_mclk1_sel"),
+ IMX_BLK_CTRL_CLK_GATE("sai1_mclk2_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI1_MCLK2, 0, 2, "sai1_mclk2_sel"),
+ IMX_BLK_CTRL_CLK_GATE("sai1_mclk3_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI1_MCLK3, 0, 3, "sai_pll_out"),
+ IMX_BLK_CTRL_CLK_GATE("sai2_ipg_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI2_IPG, 0, 4, "audio_ahb_root"),
+ IMX_BLK_CTRL_CLK_GATE("sai2_mclk1_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI2_MCLK1, 0, 5, "sai2_mclk1_sel"),
+ IMX_BLK_CTRL_CLK_GATE("sai2_mclk2_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI2_MCLK2, 0, 6, "sai2_mclk2_sel"),
+ IMX_BLK_CTRL_CLK_GATE("sai2_mclk3_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI2_MCLK3, 0, 7, "sai_pll_out"),
+ IMX_BLK_CTRL_CLK_GATE("sai3_ipg_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_IPG, 0, 8, "audio_ahb_root"),
+ IMX_BLK_CTRL_CLK_GATE("sai3_mclk1_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_MCLK1, 0, 9, "sai3_mclk1_sel"),
+ IMX_BLK_CTRL_CLK_GATE("sai3_mclk2_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_MCLK2, 0, 10, "sai3_mclk2_sel"),
+ IMX_BLK_CTRL_CLK_GATE("sai3_mclk3_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_MCLK3, 0, 11, "sai_pll_out"),
+ IMX_BLK_CTRL_CLK_GATE("sai5_ipg_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI5_IPG, 0, 12, "audio_ahb_root"),
+ IMX_BLK_CTRL_CLK_GATE("sai5_mclk1_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI5_MCLK1, 0, 13, "sai5_mclk1_sel"),
+ IMX_BLK_CTRL_CLK_GATE("sai5_mclk2_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI5_MCLK2, 0, 14, "sai5_mclk2_sel"),
+ IMX_BLK_CTRL_CLK_GATE("sai5_mclk3_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI5_MCLK3, 0, 15, "sai_pll_out"),
+ IMX_BLK_CTRL_CLK_GATE("sai6_ipg_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI6_IPG, 0, 16, "audio_ahb_root"),
+ IMX_BLK_CTRL_CLK_GATE("sai6_mclk1_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI6_MCLK1, 0, 17, "sai6_mclk1_sel"),
+ IMX_BLK_CTRL_CLK_GATE("sai6_mclk2_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI6_MCLK2, 0, 18, "sai6_mclk2_sel"),
+ IMX_BLK_CTRL_CLK_GATE("sai6_mclk3_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI6_MCLK3, 0, 19, "sai_pll_out"),
+ IMX_BLK_CTRL_CLK_GATE("sai7_ipg_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI7_IPG, 0, 20, "audio_ahb_root"),
+ IMX_BLK_CTRL_CLK_GATE("sai7_mclk1_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI7_MCLK1, 0, 21, "sai7_mclk1_sel"),
+ IMX_BLK_CTRL_CLK_GATE("sai7_mclk2_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI7_MCLK2, 0, 22, "sai7_mclk2_sel"),
+ IMX_BLK_CTRL_CLK_GATE("sai7_mclk3_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SAI7_MCLK3, 0, 23, "sai_pll_out"),
+ IMX_BLK_CTRL_CLK_GATE("asrc_ipg_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_ASRC_IPG, 0, 24, "audio_ahb_root"),
+ IMX_BLK_CTRL_CLK_SHARED_GATE("pdm_ipg_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_PDM_IPG, 0, 25, "audio_ahb_root", &shared_count_pdm),
+ IMX_BLK_CTRL_CLK_SHARED_GATE("pdm_root_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_PDM_ROOT, 0, 25, "pdm_sel", &shared_count_pdm),
+ IMX_BLK_CTRL_CLK_GATE("sdma3_root_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SDMA3_ROOT, 0, 27, "audio_ahb_root"),
+ IMX_BLK_CTRL_CLK_GATE("spba2_root_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_SPBA2_ROOT, 0, 28, "audio_ahb_root"),
+ IMX_BLK_CTRL_CLK_GATE("dsp_root_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_DSP_ROOT, 0, 29, "audio_axi_root"),
+ IMX_BLK_CTRL_CLK_GATE("dsp_dbg_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_DSPDBG_ROOT, 0, 30, "audio_axi_root"),
+ IMX_BLK_CTRL_CLK_GATE("earc_ipg_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_EARC_IPG, 0, 31, "audio_ahb_root"),
+ IMX_BLK_CTRL_CLK_GATE("ocram_a_ipg_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_OCRAMA_IPG, 4, 0, "audio_axi_root"),
+ IMX_BLK_CTRL_CLK_GATE("aud2htx_ipg_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_AUD2HTX_IPG, 4, 1, "audio_ahb_root"),
+ IMX_BLK_CTRL_CLK_GATE("edma_root_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_EDMA_ROOT, 4, 2, "audio_ahb_root"),
+ IMX_BLK_CTRL_CLK_GATE("aud_pll_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_AUDPLL_ROOT, 4, 3, "osc_24m"),
+ IMX_BLK_CTRL_CLK_GATE("mu2_root_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_MU2_ROOT, 4, 4, "audio_ahb_root"),
+ IMX_BLK_CTRL_CLK_GATE("mu3_root_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_MU3_ROOT, 4, 5, "audio_ahb_root"),
+ IMX_BLK_CTRL_CLK_GATE("earc_phy_clk", IMX8MP_CLK_AUDIO_BLK_CTRL_EARC_PHY, 4, 6, "sai_pll_out"),
+
+ /* resets */
+ IMX_BLK_CTRL_RESET(IMX8MP_AUDIO_BLK_CTRL_EARC_RESET, 0x200, 0),
+ IMX_BLK_CTRL_RESET(IMX8MP_AUDIO_BLK_CTRL_EARC_PHY_RESET, 0x200, 1),
+};
+
+const struct imx_blk_ctrl_dev_data imx8mp_hdmi_blk_ctrl_dev_data = {
+ .hws = imx8mp_hdmi_blk_ctrl_hws,
+ .hws_num = ARRAY_SIZE(imx8mp_hdmi_blk_ctrl_hws),
+ .clocks_max = IMX8MP_CLK_HDMI_BLK_CTRL_END,
+ .resets_max = IMX8MP_HDMI_BLK_CTRL_RESET_NUM,
+ .pm_runtime_saved_regs_num = 0
+};
+EXPORT_SYMBOL_GPL(imx8mp_hdmi_blk_ctrl_dev_data);
+
+const struct imx_blk_ctrl_dev_data imx8mp_media_blk_ctrl_dev_data = {
+ .hws = imx8mp_media_blk_ctrl_hws,
+ .hws_num = ARRAY_SIZE(imx8mp_media_blk_ctrl_hws),
+ .clocks_max = IMX8MP_CLK_MEDIA_BLK_CTRL_END,
+ .resets_max = IMX8MP_MEDIA_BLK_CTRL_RESET_NUM,
+ .pm_runtime_saved_regs_num = 2,
+ .pm_runtime_saved_regs = {
+ IMX_MEDIA_BLK_CTRL_SFT_RSTN,
+ IMX_MEDIA_BLK_CTRL_CLK_EN,
+ },
+};
+EXPORT_SYMBOL_GPL(imx8mp_media_blk_ctrl_dev_data);
+
+const struct imx_blk_ctrl_dev_data imx8mp_audio_blk_ctrl_dev_data = {
+ .hws = imx8mp_audio_blk_ctrl_hws,
+ .hws_num = ARRAY_SIZE(imx8mp_audio_blk_ctrl_hws),
+ .clocks_max = IMX8MP_CLK_AUDIO_BLK_CTRL_END,
+ .resets_max = IMX8MP_AUDIO_BLK_CTRL_RESET_NUM,
+ .pm_runtime_saved_regs_num = 16,
+ .pm_runtime_saved_regs = {
+ IMX_AUDIO_BLK_CTRL_CLKEN0,
+ IMX_AUDIO_BLK_CTRL_CLKEN1,
+ IMX_AUDIO_BLK_CTRL_EARC,
+ IMX_AUDIO_BLK_CTRL_SAI1_MCLK_SEL,
+ IMX_AUDIO_BLK_CTRL_SAI2_MCLK_SEL,
+ IMX_AUDIO_BLK_CTRL_SAI3_MCLK_SEL,
+ IMX_AUDIO_BLK_CTRL_SAI5_MCLK_SEL,
+ IMX_AUDIO_BLK_CTRL_SAI6_MCLK_SEL,
+ IMX_AUDIO_BLK_CTRL_SAI7_MCLK_SEL,
+ IMX_AUDIO_BLK_CTRL_PDM_CLK,
+ IMX_AUDIO_BLK_CTRL_SAI_PLL_GNRL_CTL,
+ IMX_AUDIO_BLK_CTRL_SAI_PLL_FDIVL_CTL0,
+ IMX_AUDIO_BLK_CTRL_SAI_PLL_FDIVL_CTL1,
+ IMX_AUDIO_BLK_CTRL_SAI_PLL_SSCG_CTL,
+ IMX_AUDIO_BLK_CTRL_SAI_PLL_MNIT_CTL,
+ IMX_AUDIO_BLK_CTRL_IPG_LP_CTRL
+ },
+};
+EXPORT_SYMBOL_GPL(imx8mp_audio_blk_ctrl_dev_data);
static const char * const pll_ref_sels[] = { "osc_24m", "dummy", "dummy", "dummy", };
static const char * const audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", };
@@ -128,6 +409,10 @@ static const char * const imx8mp_mipi_dsi_esc_rx_sels[] = {"osc_24m", "sys_pll2_
"sys_pll1_800m", "sys_pll2_1000m",
"sys_pll3_out", "clk_ext3", "audio_pll2_out", };
+static const char * const imx8mp_media_disp2_pix_sels[] = {"osc_24m", "video_pll1_out", "audio_pll2_out",
+ "audio_pll1_out", "sys_pll1_800m", "sys_pll2_1000m",
+ "sys_pll3_out", "clk_ext4", };
+
static const char * const imx8mp_dram_alt_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll1_100m",
"sys_pll2_500m", "sys_pll2_1000m", "sys_pll3_out",
"audio_pll1_out", "sys_pll1_266m", };
@@ -402,12 +687,42 @@ static const char * const imx8mp_dram_core_sels[] = {"dram_pll_out", "dram_alt_r
static struct clk_hw **hws;
static struct clk_hw_onecell_data *clk_hw_data;
+static int imx_clk_init_on(struct device_node *np,
+ struct clk_hw * const clks[])
+{
+ u32 *array;
+ int i, ret, elems;
+
+ elems = of_property_count_u32_elems(np, "init-on-array");
+ if (elems < 0)
+ return elems;
+ array = kcalloc(elems, sizeof(elems), GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(np, "init-on-array", array, elems);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < elems; i++) {
+ ret = clk_prepare_enable(clks[array[i]]->clk);
+ if (ret)
+ pr_err("clk_prepare_enable failed %d\n", array[i]);
+ }
+
+ kfree(array);
+
+ return 0;
+}
+
static int imx8mp_clocks_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np;
void __iomem *anatop_base, *ccm_base;
+ check_m4_enabled();
+
np = of_find_compatible_node(NULL, NULL, "fsl,imx8mp-anatop");
anatop_base = of_iomap(np, 0);
of_node_put(np);
@@ -480,44 +795,28 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
hws[IMX8MP_ARM_PLL_OUT] = imx_clk_hw_gate("arm_pll_out", "arm_pll_bypass", anatop_base + 0x84, 11);
hws[IMX8MP_SYS_PLL3_OUT] = imx_clk_hw_gate("sys_pll3_out", "sys_pll3_bypass", anatop_base + 0x114, 11);
- hws[IMX8MP_SYS_PLL1_40M_CG] = imx_clk_hw_gate("sys_pll1_40m_cg", "sys_pll1_bypass", anatop_base + 0x94, 27);
- hws[IMX8MP_SYS_PLL1_80M_CG] = imx_clk_hw_gate("sys_pll1_80m_cg", "sys_pll1_bypass", anatop_base + 0x94, 25);
- hws[IMX8MP_SYS_PLL1_100M_CG] = imx_clk_hw_gate("sys_pll1_100m_cg", "sys_pll1_bypass", anatop_base + 0x94, 23);
- hws[IMX8MP_SYS_PLL1_133M_CG] = imx_clk_hw_gate("sys_pll1_133m_cg", "sys_pll1_bypass", anatop_base + 0x94, 21);
- hws[IMX8MP_SYS_PLL1_160M_CG] = imx_clk_hw_gate("sys_pll1_160m_cg", "sys_pll1_bypass", anatop_base + 0x94, 19);
- hws[IMX8MP_SYS_PLL1_200M_CG] = imx_clk_hw_gate("sys_pll1_200m_cg", "sys_pll1_bypass", anatop_base + 0x94, 17);
- hws[IMX8MP_SYS_PLL1_266M_CG] = imx_clk_hw_gate("sys_pll1_266m_cg", "sys_pll1_bypass", anatop_base + 0x94, 15);
- hws[IMX8MP_SYS_PLL1_400M_CG] = imx_clk_hw_gate("sys_pll1_400m_cg", "sys_pll1_bypass", anatop_base + 0x94, 13);
hws[IMX8MP_SYS_PLL1_OUT] = imx_clk_hw_gate("sys_pll1_out", "sys_pll1_bypass", anatop_base + 0x94, 11);
- hws[IMX8MP_SYS_PLL1_40M] = imx_clk_hw_fixed_factor("sys_pll1_40m", "sys_pll1_40m_cg", 1, 20);
- hws[IMX8MP_SYS_PLL1_80M] = imx_clk_hw_fixed_factor("sys_pll1_80m", "sys_pll1_80m_cg", 1, 10);
- hws[IMX8MP_SYS_PLL1_100M] = imx_clk_hw_fixed_factor("sys_pll1_100m", "sys_pll1_100m_cg", 1, 8);
- hws[IMX8MP_SYS_PLL1_133M] = imx_clk_hw_fixed_factor("sys_pll1_133m", "sys_pll1_133m_cg", 1, 6);
- hws[IMX8MP_SYS_PLL1_160M] = imx_clk_hw_fixed_factor("sys_pll1_160m", "sys_pll1_160m_cg", 1, 5);
- hws[IMX8MP_SYS_PLL1_200M] = imx_clk_hw_fixed_factor("sys_pll1_200m", "sys_pll1_200m_cg", 1, 4);
- hws[IMX8MP_SYS_PLL1_266M] = imx_clk_hw_fixed_factor("sys_pll1_266m", "sys_pll1_266m_cg", 1, 3);
- hws[IMX8MP_SYS_PLL1_400M] = imx_clk_hw_fixed_factor("sys_pll1_400m", "sys_pll1_400m_cg", 1, 2);
+ hws[IMX8MP_SYS_PLL1_40M] = imx_clk_hw_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20);
+ hws[IMX8MP_SYS_PLL1_80M] = imx_clk_hw_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10);
+ hws[IMX8MP_SYS_PLL1_100M] = imx_clk_hw_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8);
+ hws[IMX8MP_SYS_PLL1_133M] = imx_clk_hw_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6);
+ hws[IMX8MP_SYS_PLL1_160M] = imx_clk_hw_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5);
+ hws[IMX8MP_SYS_PLL1_200M] = imx_clk_hw_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4);
+ hws[IMX8MP_SYS_PLL1_266M] = imx_clk_hw_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3);
+ hws[IMX8MP_SYS_PLL1_400M] = imx_clk_hw_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2);
hws[IMX8MP_SYS_PLL1_800M] = imx_clk_hw_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1);
- hws[IMX8MP_SYS_PLL2_50M_CG] = imx_clk_hw_gate("sys_pll2_50m_cg", "sys_pll2_bypass", anatop_base + 0x104, 27);
- hws[IMX8MP_SYS_PLL2_100M_CG] = imx_clk_hw_gate("sys_pll2_100m_cg", "sys_pll2_bypass", anatop_base + 0x104, 25);
- hws[IMX8MP_SYS_PLL2_125M_CG] = imx_clk_hw_gate("sys_pll2_125m_cg", "sys_pll2_bypass", anatop_base + 0x104, 23);
- hws[IMX8MP_SYS_PLL2_166M_CG] = imx_clk_hw_gate("sys_pll2_166m_cg", "sys_pll2_bypass", anatop_base + 0x104, 21);
- hws[IMX8MP_SYS_PLL2_200M_CG] = imx_clk_hw_gate("sys_pll2_200m_cg", "sys_pll2_bypass", anatop_base + 0x104, 19);
- hws[IMX8MP_SYS_PLL2_250M_CG] = imx_clk_hw_gate("sys_pll2_250m_cg", "sys_pll2_bypass", anatop_base + 0x104, 17);
- hws[IMX8MP_SYS_PLL2_333M_CG] = imx_clk_hw_gate("sys_pll2_333m_cg", "sys_pll2_bypass", anatop_base + 0x104, 15);
- hws[IMX8MP_SYS_PLL2_500M_CG] = imx_clk_hw_gate("sys_pll2_500m_cg", "sys_pll2_bypass", anatop_base + 0x104, 13);
hws[IMX8MP_SYS_PLL2_OUT] = imx_clk_hw_gate("sys_pll2_out", "sys_pll2_bypass", anatop_base + 0x104, 11);
- hws[IMX8MP_SYS_PLL2_50M] = imx_clk_hw_fixed_factor("sys_pll2_50m", "sys_pll2_50m_cg", 1, 20);
- hws[IMX8MP_SYS_PLL2_100M] = imx_clk_hw_fixed_factor("sys_pll2_100m", "sys_pll2_100m_cg", 1, 10);
- hws[IMX8MP_SYS_PLL2_125M] = imx_clk_hw_fixed_factor("sys_pll2_125m", "sys_pll2_125m_cg", 1, 8);
- hws[IMX8MP_SYS_PLL2_166M] = imx_clk_hw_fixed_factor("sys_pll2_166m", "sys_pll2_166m_cg", 1, 6);
- hws[IMX8MP_SYS_PLL2_200M] = imx_clk_hw_fixed_factor("sys_pll2_200m", "sys_pll2_200m_cg", 1, 5);
- hws[IMX8MP_SYS_PLL2_250M] = imx_clk_hw_fixed_factor("sys_pll2_250m", "sys_pll2_250m_cg", 1, 4);
- hws[IMX8MP_SYS_PLL2_333M] = imx_clk_hw_fixed_factor("sys_pll2_333m", "sys_pll2_333m_cg", 1, 3);
- hws[IMX8MP_SYS_PLL2_500M] = imx_clk_hw_fixed_factor("sys_pll2_500m", "sys_pll2_500m_cg", 1, 2);
+ hws[IMX8MP_SYS_PLL2_50M] = imx_clk_hw_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20);
+ hws[IMX8MP_SYS_PLL2_100M] = imx_clk_hw_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10);
+ hws[IMX8MP_SYS_PLL2_125M] = imx_clk_hw_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8);
+ hws[IMX8MP_SYS_PLL2_166M] = imx_clk_hw_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6);
+ hws[IMX8MP_SYS_PLL2_200M] = imx_clk_hw_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5);
+ hws[IMX8MP_SYS_PLL2_250M] = imx_clk_hw_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4);
+ hws[IMX8MP_SYS_PLL2_333M] = imx_clk_hw_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3);
+ hws[IMX8MP_SYS_PLL2_500M] = imx_clk_hw_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2);
hws[IMX8MP_SYS_PLL2_1000M] = imx_clk_hw_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1);
hws[IMX8MP_CLK_A53_DIV] = imx8m_clk_hw_composite_core("arm_a53_div", imx8mp_a53_sels, ccm_base + 0x8000);
@@ -538,7 +837,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
hws[IMX8MP_CLK_MAIN_AXI] = imx8m_clk_hw_composite_bus_critical("main_axi", imx8mp_main_axi_sels, ccm_base + 0x8800);
hws[IMX8MP_CLK_ENET_AXI] = imx8m_clk_hw_composite_bus("enet_axi", imx8mp_enet_axi_sels, ccm_base + 0x8880);
- hws[IMX8MP_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite_bus_critical("nand_usdhc_bus", imx8mp_nand_usdhc_sels, ccm_base + 0x8900);
+ hws[IMX8MP_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite("nand_usdhc_bus", imx8mp_nand_usdhc_sels, ccm_base + 0x8900);
hws[IMX8MP_CLK_VPU_BUS] = imx8m_clk_hw_composite_bus("vpu_bus", imx8mp_vpu_bus_sels, ccm_base + 0x8980);
hws[IMX8MP_CLK_MEDIA_AXI] = imx8m_clk_hw_composite_bus("media_axi", imx8mp_media_axi_sels, ccm_base + 0x8a00);
hws[IMX8MP_CLK_MEDIA_APB] = imx8m_clk_hw_composite_bus("media_apb", imx8mp_media_apb_sels, ccm_base + 0x8a80);
@@ -554,6 +853,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
hws[IMX8MP_CLK_AHB] = imx8m_clk_hw_composite_bus_critical("ahb_root", imx8mp_ahb_sels, ccm_base + 0x9000);
hws[IMX8MP_CLK_AUDIO_AHB] = imx8m_clk_hw_composite_bus("audio_ahb", imx8mp_audio_ahb_sels, ccm_base + 0x9100);
hws[IMX8MP_CLK_MIPI_DSI_ESC_RX] = imx8m_clk_hw_composite_bus("mipi_dsi_esc_rx", imx8mp_mipi_dsi_esc_rx_sels, ccm_base + 0x9200);
+ hws[IMX8MP_CLK_MEDIA_DISP2_PIX] = imx8m_clk_hw_composite_bus("media_disp2_pix", imx8mp_media_disp2_pix_sels, ccm_base + 0x9300);
hws[IMX8MP_CLK_IPG_ROOT] = imx_clk_hw_divider2("ipg_root", "ahb_root", ccm_base + 0x9080, 0, 1);
@@ -670,7 +970,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
hws[IMX8MP_CLK_SIM_ENET_ROOT] = imx_clk_hw_gate4("sim_enet_root_clk", "enet_axi", ccm_base + 0x4400, 0);
hws[IMX8MP_CLK_GPU2D_ROOT] = imx_clk_hw_gate4("gpu2d_root_clk", "gpu2d_core", ccm_base + 0x4450, 0);
hws[IMX8MP_CLK_GPU3D_ROOT] = imx_clk_hw_gate4("gpu3d_root_clk", "gpu3d_core", ccm_base + 0x4460, 0);
- hws[IMX8MP_CLK_SNVS_ROOT] = imx_clk_hw_gate4("snvs_root_clk", "ipg_root", ccm_base + 0x4470, 0);
+ hws[IMX8MP_CLK_SNVS_ROOT] = imx_clk_hw_gate2_flags("snvs_root_clk", "ipg_root", ccm_base + 0x4470, 0, CLK_IS_CRITICAL);
hws[IMX8MP_CLK_UART1_ROOT] = imx_clk_hw_gate4("uart1_root_clk", "uart1", ccm_base + 0x4490, 0);
hws[IMX8MP_CLK_UART2_ROOT] = imx_clk_hw_gate4("uart2_root_clk", "uart2", ccm_base + 0x44a0, 0);
hws[IMX8MP_CLK_UART3_ROOT] = imx_clk_hw_gate4("uart3_root_clk", "uart3", ccm_base + 0x44b0, 0);
@@ -694,13 +994,23 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
hws[IMX8MP_CLK_MEDIA_CAM2_PIX_ROOT] = imx_clk_hw_gate2_shared2("media_cam2_pix_root_clk", "media_cam2_pix", ccm_base + 0x45d0, 0, &share_count_media);
hws[IMX8MP_CLK_MEDIA_DISP1_PIX_ROOT] = imx_clk_hw_gate2_shared2("media_disp1_pix_root_clk", "media_disp1_pix", ccm_base + 0x45d0, 0, &share_count_media);
hws[IMX8MP_CLK_MEDIA_DISP2_PIX_ROOT] = imx_clk_hw_gate2_shared2("media_disp2_pix_root_clk", "media_disp2_pix", ccm_base + 0x45d0, 0, &share_count_media);
+ hws[IMX8MP_CLK_MEDIA_LDB_ROOT] = imx_clk_hw_gate2_shared2("media_ldb_root_clk", "media_ldb", ccm_base + 0x45d0, 0, &share_count_media);
hws[IMX8MP_CLK_MEDIA_ISP_ROOT] = imx_clk_hw_gate2_shared2("media_isp_root_clk", "media_isp", ccm_base + 0x45d0, 0, &share_count_media);
hws[IMX8MP_CLK_USDHC3_ROOT] = imx_clk_hw_gate4("usdhc3_root_clk", "usdhc3", ccm_base + 0x45e0, 0);
hws[IMX8MP_CLK_HDMI_ROOT] = imx_clk_hw_gate4("hdmi_root_clk", "hdmi_axi", ccm_base + 0x45f0, 0);
hws[IMX8MP_CLK_TSENSOR_ROOT] = imx_clk_hw_gate4("tsensor_root_clk", "ipg_root", ccm_base + 0x4620, 0);
hws[IMX8MP_CLK_VPU_ROOT] = imx_clk_hw_gate4("vpu_root_clk", "vpu_bus", ccm_base + 0x4630, 0);
- hws[IMX8MP_CLK_AUDIO_ROOT] = imx_clk_hw_gate4("audio_root_clk", "ipg_root", ccm_base + 0x4650, 0);
+
+ hws[IMX8MP_CLK_AUDIO_AHB_ROOT] = imx_clk_hw_gate2_shared2("audio_ahb_root", "audio_ahb", ccm_base + 0x4650, 0, &share_count_audio);
+ hws[IMX8MP_CLK_AUDIO_AXI_ROOT] = imx_clk_hw_gate2_shared2("audio_axi_root", "audio_axi", ccm_base + 0x4650, 0, &share_count_audio);
+ hws[IMX8MP_CLK_SAI1_ROOT] = imx_clk_hw_gate2_shared2("sai1_root", "sai1", ccm_base + 0x4650, 0, &share_count_audio);
+ hws[IMX8MP_CLK_SAI2_ROOT] = imx_clk_hw_gate2_shared2("sai2_root", "sai2", ccm_base + 0x4650, 0, &share_count_audio);
+ hws[IMX8MP_CLK_SAI3_ROOT] = imx_clk_hw_gate2_shared2("sai3_root", "sai3", ccm_base + 0x4650, 0, &share_count_audio);
+ hws[IMX8MP_CLK_SAI5_ROOT] = imx_clk_hw_gate2_shared2("sai5_root", "sai5", ccm_base + 0x4650, 0, &share_count_audio);
+ hws[IMX8MP_CLK_SAI6_ROOT] = imx_clk_hw_gate2_shared2("sai6_root", "sai6", ccm_base + 0x4650, 0, &share_count_audio);
+ hws[IMX8MP_CLK_SAI7_ROOT] = imx_clk_hw_gate2_shared2("sai7_root", "sai7", ccm_base + 0x4650, 0, &share_count_audio);
+ hws[IMX8MP_CLK_PDM_ROOT] = imx_clk_hw_gate2_shared2("pdm_root", "pdm", ccm_base + 0x4650, 0, &share_count_audio);
hws[IMX8MP_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core",
hws[IMX8MP_CLK_A53_CORE]->clk,
@@ -712,6 +1022,8 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
+ imx_clk_init_on(np, hws);
+
imx_register_uart_clocks(4);
return 0;
@@ -740,3 +1052,80 @@ module_platform_driver(imx8mp_clk_driver);
MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
MODULE_DESCRIPTION("NXP i.MX8MP clock driver");
MODULE_LICENSE("GPL v2");
+
+#ifndef MODULE
+/*
+ * Debugfs interface for audio PLL K divider change dynamically.
+ * Monitor control for the Audio PLL K-Divider
+ */
+#ifdef CONFIG_DEBUG_FS
+
+#define KDIV_MASK GENMASK(15, 0)
+#define MDIV_SHIFT 12
+#define MDIV_MASK GENMASK(21, 12)
+#define PDIV_SHIFT 4
+#define PDIV_MASK GENMASK(9, 4)
+#define SDIV_SHIFT 0
+#define SDIV_MASK GENMASK(2, 0)
+
+static int pll_delta_k_set(void *data, u64 val)
+{
+ struct clk_hw *hw;
+ short int delta_k;
+
+ hw = data;
+ delta_k = (short int) (val & KDIV_MASK);
+
+ clk_set_delta_k(hw, val);
+
+ pr_debug("the delta k is %d\n", delta_k);
+ return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(delta_k_fops, NULL, pll_delta_k_set, "%lld\n");
+
+static int pll_setting_show(struct seq_file *s, void *data)
+{
+ struct clk_hw *hw;
+ u32 pll_div_ctrl0, pll_div_ctrl1;
+ u32 mdiv, pdiv, sdiv, kdiv;
+
+ hw = s->private;
+
+ clk_get_pll_setting(hw, &pll_div_ctrl0, &pll_div_ctrl1);
+ mdiv = (pll_div_ctrl0 & MDIV_MASK) >> MDIV_SHIFT;
+ pdiv = (pll_div_ctrl0 & PDIV_MASK) >> PDIV_SHIFT;
+ sdiv = (pll_div_ctrl0 & SDIV_MASK) >> SDIV_SHIFT;
+ kdiv = (pll_div_ctrl1 & KDIV_MASK);
+
+ seq_printf(s, "Mdiv: 0x%x; Pdiv: 0x%x; Sdiv: 0x%x; Kdiv: 0x%x\n",
+ mdiv, pdiv, sdiv, kdiv);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(pll_setting);
+
+static int __init pll_debug_init(void)
+{
+ struct dentry *root, *audio_pll1, *audio_pll2;
+
+ if (of_machine_is_compatible("fsl,imx8mp") && hws) {
+ /* create a root dir for audio pll monitor */
+ root = debugfs_create_dir("audio_pll_monitor", NULL);
+ audio_pll1 = debugfs_create_dir("audio_pll1", root);
+ audio_pll2 = debugfs_create_dir("audio_pll2", root);
+
+ debugfs_create_file_unsafe("delta_k", 0444, audio_pll1,
+ hws[IMX8MP_AUDIO_PLL1], &delta_k_fops);
+ debugfs_create_file("pll_parameter", 0x444, audio_pll1,
+ hws[IMX8MP_AUDIO_PLL1], &pll_setting_fops);
+ debugfs_create_file_unsafe("delta_k", 0444, audio_pll2,
+ hws[IMX8MP_AUDIO_PLL2], &delta_k_fops);
+ debugfs_create_file("pll_parameter", 0x444, audio_pll2,
+ hws[IMX8MP_AUDIO_PLL2], &pll_setting_fops);
+ }
+
+ return 0;
+}
+late_initcall(pll_debug_init);
+#endif /* CONFIG_DEBUG_FS */
+#endif /* MODULE */
diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c
index 83cc2b1c3294..55323f4165a1 100644
--- a/drivers/clk/imx/clk-imx8mq.c
+++ b/drivers/clk/imx/clk-imx8mq.c
@@ -5,6 +5,7 @@
*/
#include <dt-bindings/clock/imx8mq-clock.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
@@ -13,6 +14,8 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <soc/imx/soc.h>
#include "clk.h"
@@ -25,7 +28,7 @@ static u32 share_count_sai6;
static u32 share_count_dcss;
static u32 share_count_nand;
-static const char * const pll_ref_sels[] = { "osc_25m", "osc_27m", "dummy", "dummy", };
+static const char * const pll_ref_sels[] = { "osc_25m", "osc_27m", "phy_27m", "dummy", };
static const char * const arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
static const char * const gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", };
static const char * const vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", };
@@ -281,6 +284,34 @@ static const char * const pllout_monitor_sels[] = {"osc_25m", "osc_27m", "dummy"
static struct clk_hw_onecell_data *clk_hw_data;
static struct clk_hw **hws;
+static int imx_clk_init_on(struct device_node *np,
+ struct clk_hw * const clks[])
+{
+ u32 *array;
+ int i, ret, elems;
+
+ elems = of_property_count_u32_elems(np, "init-on-array");
+ if (elems < 0)
+ return elems;
+ array = kzalloc(elems * sizeof(elems), GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(np, "init-on-array", array, elems);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < elems; i++) {
+ ret = clk_prepare_enable(clks[array[i]]->clk);
+ if (ret)
+ pr_err("clk_prepare_enable failed %d\n", array[i]);
+ }
+
+ kfree(array);
+
+ return 0;
+}
+
static int imx8mq_clocks_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -288,6 +319,8 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
void __iomem *base;
int err;
+ check_m4_enabled();
+
clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
IMX8MQ_CLK_END), GFP_KERNEL);
if (WARN_ON(!clk_hw_data))
@@ -304,6 +337,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
hws[IMX8MQ_CLK_EXT2] = imx_obtain_fixed_clk_hw(np, "clk_ext2");
hws[IMX8MQ_CLK_EXT3] = imx_obtain_fixed_clk_hw(np, "clk_ext3");
hws[IMX8MQ_CLK_EXT4] = imx_obtain_fixed_clk_hw(np, "clk_ext4");
+ hws[IMX8MQ_CLK_PHY_27MHZ] = imx_clk_hw_fixed("phy_27m", 27000000);
np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-anatop");
base = of_iomap(np, 0);
@@ -343,6 +377,13 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
hws[IMX8MQ_AUDIO_PLL2_BYPASS] = imx_clk_hw_mux("audio_pll2_bypass", base + 0x8, 14, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels));
hws[IMX8MQ_VIDEO_PLL1_BYPASS] = imx_clk_hw_mux("video_pll1_bypass", base + 0x10, 14, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels));
+ /* unbypass all the plls */
+ clk_set_parent(hws[IMX8MQ_GPU_PLL_BYPASS]->clk, hws[IMX8MQ_GPU_PLL]->clk);
+ clk_set_parent(hws[IMX8MQ_VPU_PLL_BYPASS]->clk, hws[IMX8MQ_VPU_PLL]->clk);
+ clk_set_parent(hws[IMX8MQ_AUDIO_PLL1_BYPASS]->clk, hws[IMX8MQ_AUDIO_PLL1]->clk);
+ clk_set_parent(hws[IMX8MQ_AUDIO_PLL2_BYPASS]->clk, hws[IMX8MQ_AUDIO_PLL2]->clk);
+ clk_set_parent(hws[IMX8MQ_VIDEO_PLL1_BYPASS]->clk, hws[IMX8MQ_VIDEO_PLL1]->clk);
+
/* PLL OUT GATE */
hws[IMX8MQ_ARM_PLL_OUT] = imx_clk_hw_gate("arm_pll_out", "arm_pll_bypass", base + 0x28, 21);
hws[IMX8MQ_GPU_PLL_OUT] = imx_clk_hw_gate("gpu_pll_out", "gpu_pll_bypass", base + 0x18, 21);
@@ -557,7 +598,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
hws[IMX8MQ_CLK_SAI5_IPG] = imx_clk_hw_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
hws[IMX8MQ_CLK_SAI6_ROOT] = imx_clk_hw_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6);
hws[IMX8MQ_CLK_SAI6_IPG] = imx_clk_hw_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
- hws[IMX8MQ_CLK_SNVS_ROOT] = imx_clk_hw_gate4("snvs_root_clk", "ipg_root", base + 0x4470, 0);
+ hws[IMX8MQ_CLK_SNVS_ROOT] = imx_clk_hw_gate2_flags("snvs_root_clk", "ipg_root", base + 0x4470, 0, CLK_IS_CRITICAL);
hws[IMX8MQ_CLK_UART1_ROOT] = imx_clk_hw_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
hws[IMX8MQ_CLK_UART2_ROOT] = imx_clk_hw_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
hws[IMX8MQ_CLK_UART3_ROOT] = imx_clk_hw_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
@@ -602,6 +643,16 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
goto unregister_hws;
}
+ /* enable all the clocks just for bringup */
+ imx_clk_init_on(np, hws);
+
+ clk_set_parent(hws[IMX8MQ_CLK_CSI1_CORE]->clk, hws[IMX8MQ_SYS1_PLL_266M]->clk);
+ clk_set_parent(hws[IMX8MQ_CLK_CSI1_PHY_REF]->clk, hws[IMX8MQ_SYS2_PLL_1000M]->clk);
+ clk_set_parent(hws[IMX8MQ_CLK_CSI1_ESC]->clk, hws[IMX8MQ_SYS1_PLL_800M]->clk);
+ clk_set_parent(hws[IMX8MQ_CLK_CSI2_CORE]->clk, hws[IMX8MQ_SYS1_PLL_266M]->clk);
+ clk_set_parent(hws[IMX8MQ_CLK_CSI2_PHY_REF]->clk, hws[IMX8MQ_SYS2_PLL_1000M]->clk);
+ clk_set_parent(hws[IMX8MQ_CLK_CSI2_ESC]->clk, hws[IMX8MQ_SYS1_PLL_800M]->clk);
+
imx_register_uart_clocks(4);
return 0;
diff --git a/drivers/clk/imx/clk-imx8qm-acm.c b/drivers/clk/imx/clk-imx8qm-acm.c
new file mode 100644
index 000000000000..d531294e7691
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8qm-acm.c
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ * Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+
+#include "clk.h"
+#include "clk-scu.h"
+#include "clk-imx-acm-utils.h"
+
+#include <dt-bindings/clock/imx8-clock.h>
+
+struct imx8qm_acm_priv {
+ struct clk_imx_acm_pm_domains dev_pm;
+ void __iomem *reg;
+ u32 regs[32];
+};
+
+static const char *aud_clk_sels[] = {
+ "aud_rec_clk0_lpcg_clk",
+ "aud_rec_clk1_lpcg_clk",
+ "dummy",
+ "hdmi_rx_mclk",
+ "ext_aud_mclk0",
+ "ext_aud_mclk1",
+ "esai0_rx_clk",
+ "esai0_rx_hf_clk",
+ "esai0_tx_clk",
+ "esai0_tx_hf_clk",
+ "esai1_rx_clk",
+ "esai1_rx_hf_clk",
+ "esai1_tx_clk",
+ "esai1_tx_hf_clk",
+ "spdif0_rx",
+ "spdif1_rx",
+ "sai0_rx_bclk",
+ "sai0_tx_bclk",
+ "sai1_rx_bclk",
+ "sai1_tx_bclk",
+ "sai2_rx_bclk",
+ "sai3_rx_bclk",
+ "sai4_rx_bclk",
+};
+
+static const char *mclk_out_sels[] = {
+ "aud_rec_clk0_lpcg_clk",
+ "aud_rec_clk1_lpcg_clk",
+ "dummy",
+ "hdmi_rx_mclk",
+ "spdif0_rx",
+ "spdif1_rx",
+ "sai4_rx_bclk",
+ "sai6_rx_bclk",
+};
+
+static const char *sai_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static const char *asrc_mux_clk_sels[] = {
+ "sai4_rx_bclk",
+ "sai5_tx_bclk",
+ "dummy",
+ "dummy",
+};
+
+static const char *esai_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static const char *spdif_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static const char *mqs_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static int imx8qm_acm_clk_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct clk_onecell_data *clk_data;
+ struct imx8qm_acm_priv *priv;
+ struct resource *res;
+ struct clk **clks;
+ void __iomem *base;
+ int ret;
+ int i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!base)
+ return -ENOMEM;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->reg = base;
+
+ platform_set_drvdata(pdev, priv);
+
+ clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->clks = devm_kcalloc(&pdev->dev, IMX_ADMA_ACM_CLK_END,
+ sizeof(*clk_data->clks), GFP_KERNEL);
+ if (!clk_data->clks)
+ return -ENOMEM;
+
+ clk_data->clk_num = IMX_ADMA_ACM_CLK_END;
+
+ clks = clk_data->clks;
+
+ ret = clk_imx_acm_attach_pm_domains(&pdev->dev, &priv->dev_pm);
+ if (ret)
+ return ret;
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
+ clks[IMX_ADMA_EXT_AUD_MCLK0] = imx_clk_fixed("ext_aud_mclk0", 0);
+ clks[IMX_ADMA_EXT_AUD_MCLK1] = imx_clk_fixed("ext_aud_mclk1", 0);
+ clks[IMX_ADMA_ESAI0_RX_CLK] = imx_clk_fixed("esai0_rx_clk", 0);
+ clks[IMX_ADMA_ESAI0_RX_HF_CLK] = imx_clk_fixed("esai0_rx_hf_clk", 0);
+ clks[IMX_ADMA_ESAI0_TX_CLK] = imx_clk_fixed("esai0_tx_clk", 0);
+ clks[IMX_ADMA_ESAI0_TX_HF_CLK] = imx_clk_fixed("esai0_tx_hf_clk", 0);
+ clks[IMX_ADMA_ESAI1_RX_CLK] = imx_clk_fixed("esai1_rx_clk", 0);
+ clks[IMX_ADMA_ESAI1_RX_HF_CLK] = imx_clk_fixed("esai1_rx_hf_clk", 0);
+ clks[IMX_ADMA_ESAI1_TX_CLK] = imx_clk_fixed("esai1_tx_clk", 0);
+ clks[IMX_ADMA_ESAI1_TX_HF_CLK] = imx_clk_fixed("esai1_tx_hf_clk", 0);
+ clks[IMX_ADMA_SPDIF0_RX] = imx_clk_fixed("spdif0_rx", 0);
+ clks[IMX_ADMA_SPDIF1_RX] = imx_clk_fixed("spdif1_rx", 0);
+ clks[IMX_ADMA_SAI0_RX_BCLK] = imx_clk_fixed("sai0_rx_bclk", 0);
+ clks[IMX_ADMA_SAI0_TX_BCLK] = imx_clk_fixed("sai0_tx_bclk", 0);
+ clks[IMX_ADMA_SAI1_RX_BCLK] = imx_clk_fixed("sai1_rx_bclk", 0);
+ clks[IMX_ADMA_SAI1_TX_BCLK] = imx_clk_fixed("sai1_tx_bclk", 0);
+ clks[IMX_ADMA_SAI2_RX_BCLK] = imx_clk_fixed("sai2_rx_bclk", 0);
+ clks[IMX_ADMA_SAI3_RX_BCLK] = imx_clk_fixed("sai3_rx_bclk", 0);
+ clks[IMX_ADMA_SAI4_RX_BCLK] = imx_clk_fixed("sai4_rx_bclk", 0);
+ clks[IMX_ADMA_SAI5_TX_BCLK] = imx_clk_fixed("sai5_tx_bclk", 0);
+ clks[IMX_ADMA_SAI6_RX_BCLK] = imx_clk_fixed("sai6_rx_bclk", 0);
+ clks[IMX_ADMA_HDMI_RX_MCLK] = imx_clk_fixed("hdmi_rx_mclk", 0);
+
+
+ clks[IMX_ADMA_ACM_AUD_CLK0_SEL] = imx_dev_clk_mux(dev, "acm_aud_clk0_sel", base+0x000000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels));
+ clks[IMX_ADMA_ACM_AUD_CLK1_SEL] = imx_dev_clk_mux(dev, "acm_aud_clk1_sel", base+0x010000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels));
+
+ clks[IMX_ADMA_ACM_MCLKOUT0_SEL] = imx_dev_clk_mux(dev, "acm_mclkout0_sel", base+0x020000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels));
+ clks[IMX_ADMA_ACM_MCLKOUT1_SEL] = imx_dev_clk_mux(dev, "acm_mclkout1_sel", base+0x030000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels));
+
+ clks[IMX_ADMA_ACM_ASRC0_MUX_CLK_SEL] = imx_dev_clk_mux(dev, "acm_asrc0_mclk_sel", base+0x040000, 0, 2, asrc_mux_clk_sels, ARRAY_SIZE(asrc_mux_clk_sels));
+
+ clks[IMX_ADMA_ACM_ESAI0_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_esai0_mclk_sel", base+0x060000, 0, 2, esai_mclk_sels, ARRAY_SIZE(esai_mclk_sels));
+ clks[IMX_ADMA_ACM_ESAI1_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_esai1_mclk_sel", base+0x070000, 0, 2, esai_mclk_sels, ARRAY_SIZE(esai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI0_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai0_mclk_sel", base+0x0E0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI1_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai1_mclk_sel", base+0x0F0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI2_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai2_mclk_sel", base+0x100000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI3_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai3_mclk_sel", base+0x110000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI4_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai4_mclk_sel", base+0x120000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI5_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai5_mclk_sel", base+0x130000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI6_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai6_mclk_sel", base+0x140000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI7_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai7_mclk_sel", base+0x150000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+
+ clks[IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL] = imx_dev_clk_mux(dev, "acm_spdif0_mclk_sel", base+0x1A0000, 0, 2, spdif_mclk_sels, ARRAY_SIZE(spdif_mclk_sels));
+ clks[IMX_ADMA_ACM_SPDIF1_TX_CLK_SEL] = imx_dev_clk_mux(dev, "acm_spdif1_mclk_sel", base+0x1B0000, 0, 2, spdif_mclk_sels, ARRAY_SIZE(spdif_mclk_sels));
+ clks[IMX_ADMA_ACM_MQS_TX_CLK_SEL] = imx_dev_clk_mux(dev, "acm_mqs_mclk_sel", base+0x1C0000, 0, 2, mqs_mclk_sels, ARRAY_SIZE(mqs_mclk_sels));
+
+ for (i = 0; i < clk_data->clk_num; i++) {
+ if (IS_ERR(clks[i]))
+ pr_warn("i.MX clk %u: register failed with %ld\n",
+ i, PTR_ERR(clks[i]));
+ }
+
+ ret = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+
+ pm_runtime_put_sync(&pdev->dev);
+
+ return ret;
+}
+
+static int imx8qm_acm_clk_remove(struct platform_device *pdev)
+{
+ struct imx8qm_acm_priv *priv = dev_get_drvdata(&pdev->dev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ clk_imx_acm_detach_pm_domains(&pdev->dev, &priv->dev_pm);
+
+ return 0;
+}
+
+static const struct of_device_id imx8qm_acm_match[] = {
+ { .compatible = "nxp,imx8qm-acm", },
+ { /* sentinel */ }
+};
+
+static int __maybe_unused imx8qm_acm_runtime_suspend(struct device *dev)
+{
+ struct imx8qm_acm_priv *priv = dev_get_drvdata(dev);
+
+ priv->regs[0] = readl_relaxed(priv->reg + 0x000000);
+ priv->regs[1] = readl_relaxed(priv->reg + 0x010000);
+ priv->regs[2] = readl_relaxed(priv->reg + 0x020000);
+ priv->regs[3] = readl_relaxed(priv->reg + 0x030000);
+ priv->regs[4] = readl_relaxed(priv->reg + 0x040000);
+ priv->regs[6] = readl_relaxed(priv->reg + 0x060000);
+ priv->regs[7] = readl_relaxed(priv->reg + 0x070000);
+ priv->regs[14] = readl_relaxed(priv->reg + 0x0E0000);
+ priv->regs[15] = readl_relaxed(priv->reg + 0x0F0000);
+ priv->regs[16] = readl_relaxed(priv->reg + 0x100000);
+ priv->regs[17] = readl_relaxed(priv->reg + 0x110000);
+ priv->regs[18] = readl_relaxed(priv->reg + 0x120000);
+ priv->regs[19] = readl_relaxed(priv->reg + 0x130000);
+ priv->regs[20] = readl_relaxed(priv->reg + 0x140000);
+ priv->regs[21] = readl_relaxed(priv->reg + 0x150000);
+ priv->regs[26] = readl_relaxed(priv->reg + 0x1A0000);
+ priv->regs[27] = readl_relaxed(priv->reg + 0x1B0000);
+ priv->regs[28] = readl_relaxed(priv->reg + 0x1C0000);
+
+ return 0;
+}
+
+static int __maybe_unused imx8qm_acm_runtime_resume(struct device *dev)
+{
+ struct imx8qm_acm_priv *priv = dev_get_drvdata(dev);
+
+ writel_relaxed(priv->regs[0], priv->reg + 0x000000);
+ writel_relaxed(priv->regs[1], priv->reg + 0x010000);
+ writel_relaxed(priv->regs[2], priv->reg + 0x020000);
+ writel_relaxed(priv->regs[3], priv->reg + 0x030000);
+ writel_relaxed(priv->regs[4], priv->reg + 0x040000);
+ writel_relaxed(priv->regs[6], priv->reg + 0x060000);
+ writel_relaxed(priv->regs[7], priv->reg + 0x070000);
+ writel_relaxed(priv->regs[14], priv->reg + 0x0E0000);
+ writel_relaxed(priv->regs[15], priv->reg + 0x0F0000);
+ writel_relaxed(priv->regs[16], priv->reg + 0x100000);
+ writel_relaxed(priv->regs[17], priv->reg + 0x110000);
+ writel_relaxed(priv->regs[18], priv->reg + 0x120000);
+ writel_relaxed(priv->regs[19], priv->reg + 0x130000);
+ writel_relaxed(priv->regs[20], priv->reg + 0x140000);
+ writel_relaxed(priv->regs[21], priv->reg + 0x150000);
+ writel_relaxed(priv->regs[26], priv->reg + 0x1A0000);
+ writel_relaxed(priv->regs[27], priv->reg + 0x1B0000);
+ writel_relaxed(priv->regs[28], priv->reg + 0x1C0000);
+
+ return 0;
+}
+
+static const struct dev_pm_ops imx8qm_acm_pm_ops = {
+ SET_RUNTIME_PM_OPS(imx8qm_acm_runtime_suspend,
+ imx8qm_acm_runtime_resume, NULL)
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
+static struct platform_driver imx8qm_acm_clk_driver = {
+ .driver = {
+ .name = "imx8qm-acm",
+ .of_match_table = imx8qm_acm_match,
+ .pm = &imx8qm_acm_pm_ops,
+ .suppress_bind_attrs = true,
+ },
+ .probe = imx8qm_acm_clk_probe,
+ .remove = imx8qm_acm_clk_remove,
+};
+
+static int __init imx8qm_acm_init(void)
+{
+ return platform_driver_register(&imx8qm_acm_clk_driver);
+}
+fs_initcall(imx8qm_acm_init);
diff --git a/drivers/clk/imx/clk-imx8qm-rsrc.c b/drivers/clk/imx/clk-imx8qm-rsrc.c
index 87e0b6ac027e..77f678f3a5be 100644
--- a/drivers/clk/imx/clk-imx8qm-rsrc.c
+++ b/drivers/clk/imx/clk-imx8qm-rsrc.c
@@ -43,6 +43,8 @@ static const u32 imx8qm_clk_scu_rsrc_table[] = {
IMX_SC_R_FTM_0,
IMX_SC_R_FTM_1,
IMX_SC_R_CAN_0,
+ IMX_SC_R_CAN_1,
+ IMX_SC_R_CAN_2,
IMX_SC_R_GPU_0_PID0,
IMX_SC_R_GPU_1_PID0,
IMX_SC_R_PWM_0,
@@ -65,7 +67,6 @@ static const u32 imx8qm_clk_scu_rsrc_table[] = {
IMX_SC_R_SDHC_2,
IMX_SC_R_ENET_0,
IMX_SC_R_ENET_1,
- IMX_SC_R_MLB_0,
IMX_SC_R_USB_2,
IMX_SC_R_NAND,
IMX_SC_R_LVDS_0,
diff --git a/drivers/clk/imx/clk-imx8qxp-acm.c b/drivers/clk/imx/clk-imx8qxp-acm.c
new file mode 100644
index 000000000000..8968061cf583
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8qxp-acm.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ * Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+
+#include "clk.h"
+#include "clk-scu.h"
+#include "clk-imx-acm-utils.h"
+
+#include <dt-bindings/clock/imx8-clock.h>
+
+struct imx8qxp_acm_priv {
+ struct clk_imx_acm_pm_domains dev_pm;
+ void __iomem *reg;
+ u32 regs[0x20];
+};
+
+static const char *aud_clk_sels[] = {
+ "aud_rec_clk0_lpcg_clk",
+ "aud_rec_clk1_lpcg_clk",
+ "ext_aud_mclk0",
+ "ext_aud_mclk1",
+ "esai0_rx_clk",
+ "esai0_rx_hf_clk",
+ "esai0_tx_clk",
+ "esai0_tx_hf_clk",
+ "spdif0_rx",
+ "sai0_rx_bclk",
+ "sai0_tx_bclk",
+ "sai1_rx_bclk",
+ "sai1_tx_bclk",
+ "sai2_rx_bclk",
+ "sai3_rx_bclk",
+};
+
+static const char *mclk_out_sels[] = {
+ "aud_rec_clk0_lpcg_clk",
+ "aud_rec_clk1_lpcg_clk",
+ "dummy",
+ "dummy",
+ "spdif0_rx",
+ "dummy",
+ "dummy",
+ "sai4_rx_bclk",
+};
+
+static const char *sai_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static const char *esai_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static const char *spdif_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static const char *mqs_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static int imx8qxp_acm_clk_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct clk_onecell_data *clk_data;
+ struct imx8qxp_acm_priv *priv;
+ struct resource *res;
+ struct clk **clks;
+ void __iomem *base;
+ int ret;
+ int i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!base)
+ return -ENOMEM;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->reg = base;
+
+ platform_set_drvdata(pdev, priv);
+
+ clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->clks = devm_kcalloc(&pdev->dev, IMX_ADMA_ACM_CLK_END,
+ sizeof(*clk_data->clks), GFP_KERNEL);
+ if (!clk_data->clks)
+ return -ENOMEM;
+
+ clk_data->clk_num = IMX_ADMA_ACM_CLK_END;
+
+ clks = clk_data->clks;
+
+ ret = clk_imx_acm_attach_pm_domains(&pdev->dev, &priv->dev_pm);
+ if (ret)
+ return ret;
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
+ clks[IMX_ADMA_EXT_AUD_MCLK0] = imx_clk_fixed("ext_aud_mclk0", 0);
+ clks[IMX_ADMA_EXT_AUD_MCLK1] = imx_clk_fixed("ext_aud_mclk1", 0);
+ clks[IMX_ADMA_ESAI0_RX_CLK] = imx_clk_fixed("esai0_rx_clk", 0);
+ clks[IMX_ADMA_ESAI0_RX_HF_CLK] = imx_clk_fixed("esai0_rx_hf_clk", 0);
+ clks[IMX_ADMA_ESAI0_TX_CLK] = imx_clk_fixed("esai0_tx_clk", 0);
+ clks[IMX_ADMA_ESAI0_TX_HF_CLK] = imx_clk_fixed("esai0_tx_hf_clk", 0);
+ clks[IMX_ADMA_SPDIF0_RX] = imx_clk_fixed("spdif0_rx", 0);
+ clks[IMX_ADMA_SAI0_RX_BCLK] = imx_clk_fixed("sai0_rx_bclk", 0);
+ clks[IMX_ADMA_SAI0_TX_BCLK] = imx_clk_fixed("sai0_tx_bclk", 0);
+ clks[IMX_ADMA_SAI1_RX_BCLK] = imx_clk_fixed("sai1_rx_bclk", 0);
+ clks[IMX_ADMA_SAI1_TX_BCLK] = imx_clk_fixed("sai1_tx_bclk", 0);
+ clks[IMX_ADMA_SAI2_RX_BCLK] = imx_clk_fixed("sai2_rx_bclk", 0);
+ clks[IMX_ADMA_SAI3_RX_BCLK] = imx_clk_fixed("sai3_rx_bclk", 0);
+ clks[IMX_ADMA_SAI4_RX_BCLK] = imx_clk_fixed("sai4_rx_bclk", 0);
+
+
+ clks[IMX_ADMA_ACM_AUD_CLK0_SEL] = imx_dev_clk_mux(dev, "acm_aud_clk0_sel", base+0x000000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels));
+ clks[IMX_ADMA_ACM_AUD_CLK1_SEL] = imx_dev_clk_mux(dev, "acm_aud_clk1_sel", base+0x010000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels));
+
+ clks[IMX_ADMA_ACM_MCLKOUT0_SEL] = imx_dev_clk_mux(dev, "acm_mclkout0_sel", base+0x020000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels));
+ clks[IMX_ADMA_ACM_MCLKOUT1_SEL] = imx_dev_clk_mux(dev, "acm_mclkout1_sel", base+0x030000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels));
+
+ clks[IMX_ADMA_ACM_ESAI0_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_esai0_mclk_sel", base+0x060000, 0, 2, esai_mclk_sels, ARRAY_SIZE(esai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI0_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai0_mclk_sel", base+0x0E0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI1_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai1_mclk_sel", base+0x0F0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI2_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai2_mclk_sel", base+0x100000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI3_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai3_mclk_sel", base+0x110000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI4_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai4_mclk_sel", base+0x140000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI5_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai5_mclk_sel", base+0x150000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+
+ clks[IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL] = imx_dev_clk_mux(dev, "acm_spdif0_mclk_sel", base+0x1A0000, 0, 2, spdif_mclk_sels, ARRAY_SIZE(spdif_mclk_sels));
+ clks[IMX_ADMA_ACM_MQS_TX_CLK_SEL] = imx_dev_clk_mux(dev, "acm_mqs_mclk_sel", base+0x1C0000, 0, 2, mqs_mclk_sels, ARRAY_SIZE(mqs_mclk_sels));
+
+ for (i = 0; i < clk_data->clk_num; i++) {
+ if (IS_ERR(clks[i]))
+ pr_warn("i.MX clk %u: register failed with %ld\n",
+ i, PTR_ERR(clks[i]));
+ }
+
+ ret = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+
+ pm_runtime_put_sync(&pdev->dev);
+
+ return ret;
+}
+
+static int imx8qxp_acm_clk_remove(struct platform_device *pdev)
+{
+ struct imx8qxp_acm_priv *priv = dev_get_drvdata(&pdev->dev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ clk_imx_acm_detach_pm_domains(&pdev->dev, &priv->dev_pm);
+
+ return 0;
+}
+
+static const struct of_device_id imx8qxp_acm_match[] = {
+ { .compatible = "nxp,imx8qxp-acm", },
+ { /* sentinel */ }
+};
+
+static int __maybe_unused imx8qxp_acm_runtime_suspend(struct device *dev)
+{
+ struct imx8qxp_acm_priv *priv = dev_get_drvdata(dev);
+
+ priv->regs[0] = readl_relaxed(priv->reg + 0x000000);
+ priv->regs[1] = readl_relaxed(priv->reg + 0x010000);
+ priv->regs[2] = readl_relaxed(priv->reg + 0x020000);
+ priv->regs[3] = readl_relaxed(priv->reg + 0x030000);
+ priv->regs[6] = readl_relaxed(priv->reg + 0x060000);
+ priv->regs[14] = readl_relaxed(priv->reg + 0x0E0000);
+ priv->regs[15] = readl_relaxed(priv->reg + 0x0F0000);
+ priv->regs[16] = readl_relaxed(priv->reg + 0x100000);
+ priv->regs[17] = readl_relaxed(priv->reg + 0x110000);
+ priv->regs[20] = readl_relaxed(priv->reg + 0x140000);
+ priv->regs[21] = readl_relaxed(priv->reg + 0x150000);
+ priv->regs[26] = readl_relaxed(priv->reg + 0x1A0000);
+ priv->regs[28] = readl_relaxed(priv->reg + 0x1C0000);
+
+ return 0;
+}
+
+static int __maybe_unused imx8qxp_acm_runtime_resume(struct device *dev)
+{
+ struct imx8qxp_acm_priv *priv = dev_get_drvdata(dev);
+
+ writel_relaxed(priv->regs[0], priv->reg + 0x000000);
+ writel_relaxed(priv->regs[1], priv->reg + 0x010000);
+ writel_relaxed(priv->regs[2], priv->reg + 0x020000);
+ writel_relaxed(priv->regs[3], priv->reg + 0x030000);
+ writel_relaxed(priv->regs[6], priv->reg + 0x060000);
+ writel_relaxed(priv->regs[14], priv->reg + 0x0E0000);
+ writel_relaxed(priv->regs[15], priv->reg + 0x0F0000);
+ writel_relaxed(priv->regs[16], priv->reg + 0x100000);
+ writel_relaxed(priv->regs[17], priv->reg + 0x110000);
+ writel_relaxed(priv->regs[20], priv->reg + 0x140000);
+ writel_relaxed(priv->regs[21], priv->reg + 0x150000);
+ writel_relaxed(priv->regs[26], priv->reg + 0x1A0000);
+ writel_relaxed(priv->regs[28], priv->reg + 0x1C0000);
+
+ return 0;
+}
+
+const struct dev_pm_ops imx8qxp_acm_pm_ops = {
+ SET_RUNTIME_PM_OPS(imx8qxp_acm_runtime_suspend,
+ imx8qxp_acm_runtime_resume, NULL)
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
+static struct platform_driver imx8qxp_acm_clk_driver = {
+ .driver = {
+ .name = "imx8qxp-acm",
+ .of_match_table = imx8qxp_acm_match,
+ .pm = &imx8qxp_acm_pm_ops,
+ .suppress_bind_attrs = true,
+ },
+ .probe = imx8qxp_acm_clk_probe,
+ .remove = imx8qxp_acm_clk_remove,
+};
+
+static int __init imx8qxp_acm_init(void)
+{
+ return platform_driver_register(&imx8qxp_acm_clk_driver);
+}
+fs_initcall(imx8qxp_acm_init);
diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.c b/drivers/clk/imx/clk-imx8qxp-lpcg.c
index b23758083ce5..abd969aad5a4 100644
--- a/drivers/clk/imx/clk-imx8qxp-lpcg.c
+++ b/drivers/clk/imx/clk-imx8qxp-lpcg.c
@@ -16,168 +16,12 @@
#include <linux/slab.h>
#include "clk-scu.h"
-#include "clk-imx8qxp-lpcg.h"
-
-#include <dt-bindings/clock/imx8-clock.h>
-
-/*
- * struct imx8qxp_lpcg_data - Description of one LPCG clock
- * @id: clock ID
- * @name: clock name
- * @parent: parent clock name
- * @flags: common clock flags
- * @offset: offset of this LPCG clock
- * @bit_idx: bit index of this LPCG clock
- * @hw_gate: whether supports HW autogate
- *
- * This structure describes one LPCG clock
- */
-struct imx8qxp_lpcg_data {
- int id;
- char *name;
- char *parent;
- unsigned long flags;
- u32 offset;
- u8 bit_idx;
- bool hw_gate;
-};
-
-/*
- * struct imx8qxp_ss_lpcg - Description of one subsystem LPCG clocks
- * @lpcg: LPCG clocks array of one subsystem
- * @num_lpcg: the number of LPCG clocks
- * @num_max: the maximum number of LPCG clocks
- *
- * This structure describes each subsystem LPCG clocks information
- * which then will be used to create respective LPCGs clocks
- */
-struct imx8qxp_ss_lpcg {
- const struct imx8qxp_lpcg_data *lpcg;
- u8 num_lpcg;
- u8 num_max;
-};
-
-static const struct imx8qxp_lpcg_data imx8qxp_lpcg_adma[] = {
- { IMX_ADMA_LPCG_UART0_IPG_CLK, "uart0_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_0_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_UART0_BAUD_CLK, "uart0_lpcg_baud_clk", "uart0_clk", 0, ADMA_LPUART_0_LPCG, 0, 0, },
- { IMX_ADMA_LPCG_UART1_IPG_CLK, "uart1_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_1_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_UART1_BAUD_CLK, "uart1_lpcg_baud_clk", "uart1_clk", 0, ADMA_LPUART_1_LPCG, 0, 0, },
- { IMX_ADMA_LPCG_UART2_IPG_CLK, "uart2_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_2_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_UART2_BAUD_CLK, "uart2_lpcg_baud_clk", "uart2_clk", 0, ADMA_LPUART_2_LPCG, 0, 0, },
- { IMX_ADMA_LPCG_UART3_IPG_CLK, "uart3_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_3_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_UART3_BAUD_CLK, "uart3_lpcg_baud_clk", "uart3_clk", 0, ADMA_LPUART_3_LPCG, 0, 0, },
- { IMX_ADMA_LPCG_I2C0_IPG_CLK, "i2c0_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_0_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_I2C0_CLK, "i2c0_lpcg_clk", "i2c0_clk", 0, ADMA_LPI2C_0_LPCG, 0, 0, },
- { IMX_ADMA_LPCG_I2C1_IPG_CLK, "i2c1_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_1_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_I2C1_CLK, "i2c1_lpcg_clk", "i2c1_clk", 0, ADMA_LPI2C_1_LPCG, 0, 0, },
- { IMX_ADMA_LPCG_I2C2_IPG_CLK, "i2c2_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_2_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_I2C2_CLK, "i2c2_lpcg_clk", "i2c2_clk", 0, ADMA_LPI2C_2_LPCG, 0, 0, },
- { IMX_ADMA_LPCG_I2C3_IPG_CLK, "i2c3_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_3_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_I2C3_CLK, "i2c3_lpcg_clk", "i2c3_clk", 0, ADMA_LPI2C_3_LPCG, 0, 0, },
-
- { IMX_ADMA_LPCG_DSP_CORE_CLK, "dsp_lpcg_core_clk", "dma_ipg_clk_root", 0, ADMA_HIFI_LPCG, 28, 0, },
- { IMX_ADMA_LPCG_DSP_IPG_CLK, "dsp_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_HIFI_LPCG, 20, 0, },
- { IMX_ADMA_LPCG_DSP_ADB_CLK, "dsp_lpcg_adb_clk", "dma_ipg_clk_root", 0, ADMA_HIFI_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_OCRAM_IPG_CLK, "ocram_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_OCRAM_LPCG, 16, 0, },
-};
-
-static const struct imx8qxp_ss_lpcg imx8qxp_ss_adma = {
- .lpcg = imx8qxp_lpcg_adma,
- .num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_adma),
- .num_max = IMX_ADMA_LPCG_CLK_END,
-};
-
-static const struct imx8qxp_lpcg_data imx8qxp_lpcg_conn[] = {
- { IMX_CONN_LPCG_SDHC0_PER_CLK, "sdhc0_lpcg_per_clk", "sdhc0_clk", 0, CONN_USDHC_0_LPCG, 0, 0, },
- { IMX_CONN_LPCG_SDHC0_IPG_CLK, "sdhc0_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_0_LPCG, 16, 0, },
- { IMX_CONN_LPCG_SDHC0_HCLK, "sdhc0_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_0_LPCG, 20, 0, },
- { IMX_CONN_LPCG_SDHC1_PER_CLK, "sdhc1_lpcg_per_clk", "sdhc1_clk", 0, CONN_USDHC_1_LPCG, 0, 0, },
- { IMX_CONN_LPCG_SDHC1_IPG_CLK, "sdhc1_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_1_LPCG, 16, 0, },
- { IMX_CONN_LPCG_SDHC1_HCLK, "sdhc1_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_1_LPCG, 20, 0, },
- { IMX_CONN_LPCG_SDHC2_PER_CLK, "sdhc2_lpcg_per_clk", "sdhc2_clk", 0, CONN_USDHC_2_LPCG, 0, 0, },
- { IMX_CONN_LPCG_SDHC2_IPG_CLK, "sdhc2_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_2_LPCG, 16, 0, },
- { IMX_CONN_LPCG_SDHC2_HCLK, "sdhc2_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_2_LPCG, 20, 0, },
- { IMX_CONN_LPCG_ENET0_ROOT_CLK, "enet0_ipg_root_clk", "enet0_clk", 0, CONN_ENET_0_LPCG, 0, 0, },
- { IMX_CONN_LPCG_ENET0_TX_CLK, "enet0_tx_clk", "enet0_clk", 0, CONN_ENET_0_LPCG, 4, 0, },
- { IMX_CONN_LPCG_ENET0_AHB_CLK, "enet0_ahb_clk", "conn_axi_clk_root", 0, CONN_ENET_0_LPCG, 8, 0, },
- { IMX_CONN_LPCG_ENET0_IPG_S_CLK, "enet0_ipg_s_clk", "conn_ipg_clk_root", 0, CONN_ENET_0_LPCG, 20, 0, },
- { IMX_CONN_LPCG_ENET0_IPG_CLK, "enet0_ipg_clk", "enet0_ipg_s_clk", 0, CONN_ENET_0_LPCG, 16, 0, },
- { IMX_CONN_LPCG_ENET1_ROOT_CLK, "enet1_ipg_root_clk", "enet1_clk", 0, CONN_ENET_1_LPCG, 0, 0, },
- { IMX_CONN_LPCG_ENET1_TX_CLK, "enet1_tx_clk", "enet1_clk", 0, CONN_ENET_1_LPCG, 4, 0, },
- { IMX_CONN_LPCG_ENET1_AHB_CLK, "enet1_ahb_clk", "conn_axi_clk_root", 0, CONN_ENET_1_LPCG, 8, 0, },
- { IMX_CONN_LPCG_ENET1_IPG_S_CLK, "enet1_ipg_s_clk", "conn_ipg_clk_root", 0, CONN_ENET_1_LPCG, 20, 0, },
- { IMX_CONN_LPCG_ENET1_IPG_CLK, "enet1_ipg_clk", "enet0_ipg_s_clk", 0, CONN_ENET_1_LPCG, 16, 0, },
-};
-
-static const struct imx8qxp_ss_lpcg imx8qxp_ss_conn = {
- .lpcg = imx8qxp_lpcg_conn,
- .num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_conn),
- .num_max = IMX_CONN_LPCG_CLK_END,
-};
-
-static const struct imx8qxp_lpcg_data imx8qxp_lpcg_lsio[] = {
- { IMX_LSIO_LPCG_PWM0_IPG_CLK, "pwm0_lpcg_ipg_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 0, 0, },
- { IMX_LSIO_LPCG_PWM0_IPG_HF_CLK, "pwm0_lpcg_ipg_hf_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 4, 0, },
- { IMX_LSIO_LPCG_PWM0_IPG_S_CLK, "pwm0_lpcg_ipg_s_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 16, 0, },
- { IMX_LSIO_LPCG_PWM0_IPG_SLV_CLK, "pwm0_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_0_LPCG, 20, 0, },
- { IMX_LSIO_LPCG_PWM0_IPG_MSTR_CLK, "pwm0_lpcg_ipg_mstr_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 24, 0, },
- { IMX_LSIO_LPCG_PWM1_IPG_CLK, "pwm1_lpcg_ipg_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 0, 0, },
- { IMX_LSIO_LPCG_PWM1_IPG_HF_CLK, "pwm1_lpcg_ipg_hf_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 4, 0, },
- { IMX_LSIO_LPCG_PWM1_IPG_S_CLK, "pwm1_lpcg_ipg_s_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 16, 0, },
- { IMX_LSIO_LPCG_PWM1_IPG_SLV_CLK, "pwm1_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_1_LPCG, 20, 0, },
- { IMX_LSIO_LPCG_PWM1_IPG_MSTR_CLK, "pwm1_lpcg_ipg_mstr_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 24, 0, },
- { IMX_LSIO_LPCG_PWM2_IPG_CLK, "pwm2_lpcg_ipg_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 0, 0, },
- { IMX_LSIO_LPCG_PWM2_IPG_HF_CLK, "pwm2_lpcg_ipg_hf_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 4, 0, },
- { IMX_LSIO_LPCG_PWM2_IPG_S_CLK, "pwm2_lpcg_ipg_s_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 16, 0, },
- { IMX_LSIO_LPCG_PWM2_IPG_SLV_CLK, "pwm2_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_2_LPCG, 20, 0, },
- { IMX_LSIO_LPCG_PWM2_IPG_MSTR_CLK, "pwm2_lpcg_ipg_mstr_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 24, 0, },
- { IMX_LSIO_LPCG_PWM3_IPG_CLK, "pwm3_lpcg_ipg_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 0, 0, },
- { IMX_LSIO_LPCG_PWM3_IPG_HF_CLK, "pwm3_lpcg_ipg_hf_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 4, 0, },
- { IMX_LSIO_LPCG_PWM3_IPG_S_CLK, "pwm3_lpcg_ipg_s_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 16, 0, },
- { IMX_LSIO_LPCG_PWM3_IPG_SLV_CLK, "pwm3_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_3_LPCG, 20, 0, },
- { IMX_LSIO_LPCG_PWM3_IPG_MSTR_CLK, "pwm3_lpcg_ipg_mstr_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 24, 0, },
- { IMX_LSIO_LPCG_PWM4_IPG_CLK, "pwm4_lpcg_ipg_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 0, 0, },
- { IMX_LSIO_LPCG_PWM4_IPG_HF_CLK, "pwm4_lpcg_ipg_hf_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 4, 0, },
- { IMX_LSIO_LPCG_PWM4_IPG_S_CLK, "pwm4_lpcg_ipg_s_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 16, 0, },
- { IMX_LSIO_LPCG_PWM4_IPG_SLV_CLK, "pwm4_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_4_LPCG, 20, 0, },
- { IMX_LSIO_LPCG_PWM4_IPG_MSTR_CLK, "pwm4_lpcg_ipg_mstr_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 24, 0, },
- { IMX_LSIO_LPCG_PWM5_IPG_CLK, "pwm5_lpcg_ipg_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 0, 0, },
- { IMX_LSIO_LPCG_PWM5_IPG_HF_CLK, "pwm5_lpcg_ipg_hf_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 4, 0, },
- { IMX_LSIO_LPCG_PWM5_IPG_S_CLK, "pwm5_lpcg_ipg_s_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 16, 0, },
- { IMX_LSIO_LPCG_PWM5_IPG_SLV_CLK, "pwm5_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_5_LPCG, 20, 0, },
- { IMX_LSIO_LPCG_PWM5_IPG_MSTR_CLK, "pwm5_lpcg_ipg_mstr_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 24, 0, },
- { IMX_LSIO_LPCG_PWM6_IPG_CLK, "pwm6_lpcg_ipg_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 0, 0, },
- { IMX_LSIO_LPCG_PWM6_IPG_HF_CLK, "pwm6_lpcg_ipg_hf_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 4, 0, },
- { IMX_LSIO_LPCG_PWM6_IPG_S_CLK, "pwm6_lpcg_ipg_s_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 16, 0, },
- { IMX_LSIO_LPCG_PWM6_IPG_SLV_CLK, "pwm6_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_6_LPCG, 20, 0, },
- { IMX_LSIO_LPCG_PWM6_IPG_MSTR_CLK, "pwm6_lpcg_ipg_mstr_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 24, 0, },
-};
-
-static const struct imx8qxp_ss_lpcg imx8qxp_ss_lsio = {
- .lpcg = imx8qxp_lpcg_lsio,
- .num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_lsio),
- .num_max = IMX_LSIO_LPCG_CLK_END,
-};
#define IMX_LPCG_MAX_CLKS 8
-static struct clk_hw *imx_lpcg_of_clk_src_get(struct of_phandle_args *clkspec,
- void *data)
-{
- struct clk_hw_onecell_data *hw_data = data;
- unsigned int idx = clkspec->args[0] / 4;
-
- if (idx >= hw_data->num) {
- pr_err("%s: invalid index %u\n", __func__, idx);
- return ERR_PTR(-EINVAL);
- }
-
- return hw_data->hws[idx];
-}
-
-static int imx_lpcg_parse_clks_from_dt(struct platform_device *pdev,
- struct device_node *np)
+static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
const char *output_names[IMX_LPCG_MAX_CLKS];
const char *parent_names[IMX_LPCG_MAX_CLKS];
unsigned int bit_offset[IMX_LPCG_MAX_CLKS];
@@ -185,88 +29,78 @@ static int imx_lpcg_parse_clks_from_dt(struct platform_device *pdev,
struct clk_hw **clk_hws;
struct resource *res;
void __iomem *base;
+ bool autogate;
int count;
- int idx;
int ret;
int i;
- if (!of_device_is_compatible(np, "fsl,imx8qxp-lpcg"))
- return -EINVAL;
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
- count = of_property_count_u32_elems(np, "clock-indices");
+ count = of_property_count_u32_elems(np, "bit-offset");
if (count < 0) {
dev_err(&pdev->dev, "failed to count clocks\n");
return -EINVAL;
}
- /*
- * A trick here is that we set the num of clks to the MAX instead
- * of the count from clock-indices because one LPCG supports up to
- * 8 clock outputs which each of them is fixed to 4 bits. Then we can
- * easily get the clock by clk-indices (bit-offset) / 4.
- * And the cost is very limited few pointers.
- */
-
- clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws,
- IMX_LPCG_MAX_CLKS), GFP_KERNEL);
+ clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws, count),
+ GFP_KERNEL);
if (!clk_data)
return -ENOMEM;
- clk_data->num = IMX_LPCG_MAX_CLKS;
+ clk_data->num = count;
clk_hws = clk_data->hws;
- ret = of_property_read_u32_array(np, "clock-indices", bit_offset,
- count);
+ ret = of_property_read_u32_array(np, "bit-offset", bit_offset,
+ clk_data->num);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to read clock-indices\n");
+ dev_err(&pdev->dev, "failed to read clocks bit-offset\n");
return -EINVAL;
}
- ret = of_clk_parent_fill(np, parent_names, count);
- if (ret != count) {
+ ret = of_clk_parent_fill(np, parent_names, clk_data->num);
+ if (ret != clk_data->num) {
dev_err(&pdev->dev, "failed to get clock parent names\n");
- return count;
+ return -EINVAL;
}
ret = of_property_read_string_array(np, "clock-output-names",
- output_names, count);
- if (ret != count) {
+ output_names, clk_data->num);
+ if (ret != clk_data->num) {
dev_err(&pdev->dev, "failed to read clock-output-names\n");
return -EINVAL;
}
+ autogate = of_property_read_bool(np, "hw-autogate");
+
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- for (i = 0; i < count; i++) {
- idx = bit_offset[i] / 4;
- if (idx > IMX_LPCG_MAX_CLKS) {
+ for (i = 0; i < clk_data->num; i++) {
+ if (bit_offset[i] > 31) {
dev_warn(&pdev->dev, "invalid bit offset of clock %d\n",
i);
ret = -EINVAL;
goto unreg;
}
- clk_hws[idx] = imx_clk_lpcg_scu_dev(&pdev->dev, output_names[i],
- parent_names[i], 0, base,
- bit_offset[i], false);
- if (IS_ERR(clk_hws[idx])) {
+ clk_hws[i] = imx_clk_lpcg_scu_dev(&pdev->dev, output_names[i],
+ parent_names[i], 0, base,
+ bit_offset[i], autogate);
+ if (IS_ERR(clk_hws[i])) {
dev_warn(&pdev->dev, "failed to register clock %d\n",
- idx);
- ret = PTR_ERR(clk_hws[idx]);
+ i);
+ ret = PTR_ERR(clk_hws[i]);
goto unreg;
}
}
- ret = devm_of_clk_add_hw_provider(&pdev->dev, imx_lpcg_of_clk_src_get,
+ ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,
clk_data);
if (ret)
goto unreg;
@@ -278,9 +112,8 @@ static int imx_lpcg_parse_clks_from_dt(struct platform_device *pdev,
unreg:
while (--i >= 0) {
- idx = bit_offset[i] / 4;
- if (clk_hws[idx])
- imx_clk_lpcg_scu_unregister(clk_hws[idx]);
+ if (clk_hws[i])
+ imx_clk_lpcg_scu_unregister(clk_hws[i]);
}
pm_runtime_disable(&pdev->dev);
@@ -288,74 +121,7 @@ unreg:
return ret;
}
-static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- struct clk_hw_onecell_data *clk_data;
- const struct imx8qxp_ss_lpcg *ss_lpcg;
- const struct imx8qxp_lpcg_data *lpcg;
- struct resource *res;
- struct clk_hw **clks;
- void __iomem *base;
- int ret;
- int i;
-
- /* try new binding to parse clocks from device tree first */
- ret = imx_lpcg_parse_clks_from_dt(pdev, np);
- if (!ret)
- return 0;
-
- ss_lpcg = of_device_get_match_data(dev);
- if (!ss_lpcg)
- return -ENODEV;
-
- /*
- * Please don't replace this with devm_platform_ioremap_resource.
- *
- * devm_platform_ioremap_resource calls devm_ioremap_resource which
- * differs from devm_ioremap by also calling devm_request_mem_region
- * and preventing other mappings in the same area.
- *
- * On imx8 the LPCG nodes map entire subsystems and overlap
- * peripherals, this means that using devm_platform_ioremap_resource
- * will cause many devices to fail to probe including serial ports.
- */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -EINVAL;
- base = devm_ioremap(dev, res->start, resource_size(res));
- if (!base)
- return -ENOMEM;
-
- clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws,
- ss_lpcg->num_max), GFP_KERNEL);
- if (!clk_data)
- return -ENOMEM;
-
- clk_data->num = ss_lpcg->num_max;
- clks = clk_data->hws;
-
- for (i = 0; i < ss_lpcg->num_lpcg; i++) {
- lpcg = ss_lpcg->lpcg + i;
- clks[lpcg->id] = imx_clk_lpcg_scu(lpcg->name, lpcg->parent,
- lpcg->flags, base + lpcg->offset,
- lpcg->bit_idx, lpcg->hw_gate);
- }
-
- for (i = 0; i < clk_data->num; i++) {
- if (IS_ERR(clks[i]))
- pr_warn("i.MX clk %u: register failed with %ld\n",
- i, PTR_ERR(clks[i]));
- }
-
- return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
-}
-
static const struct of_device_id imx8qxp_lpcg_match[] = {
- { .compatible = "fsl,imx8qxp-lpcg-adma", &imx8qxp_ss_adma, },
- { .compatible = "fsl,imx8qxp-lpcg-conn", &imx8qxp_ss_conn, },
- { .compatible = "fsl,imx8qxp-lpcg-lsio", &imx8qxp_ss_lsio, },
{ .compatible = "fsl,imx8qxp-lpcg", NULL },
{ /* sentinel */ }
};
diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.h b/drivers/clk/imx/clk-imx8qxp-lpcg.h
index 2a37ce57c500..ebca8fa9268f 100644
--- a/drivers/clk/imx/clk-imx8qxp-lpcg.h
+++ b/drivers/clk/imx/clk-imx8qxp-lpcg.h
@@ -42,7 +42,6 @@
#define CONN_ENET_0_LPCG 0x30000
#define CONN_ENET_1_LPCG 0x40000
#define CONN_DTCP_LPCG 0x50000
-#define CONN_MLB_LPCG 0x60000
#define CONN_USB_2_LPCG 0x70000
#define CONN_USB_3_LPCG 0x80000
#define CONN_NAND_LPCG 0x90000
diff --git a/drivers/clk/imx/clk-imx8qxp-rsrc.c b/drivers/clk/imx/clk-imx8qxp-rsrc.c
index df09f2a7996d..585c425524a4 100644
--- a/drivers/clk/imx/clk-imx8qxp-rsrc.c
+++ b/drivers/clk/imx/clk-imx8qxp-rsrc.c
@@ -54,15 +54,17 @@ static const u32 imx8qxp_clk_scu_rsrc_table[] = {
IMX_SC_R_SDHC_2,
IMX_SC_R_ENET_0,
IMX_SC_R_ENET_1,
- IMX_SC_R_MLB_0,
IMX_SC_R_USB_2,
IMX_SC_R_NAND,
IMX_SC_R_LVDS_0,
IMX_SC_R_LVDS_1,
+ IMX_SC_R_M4_0_UART,
IMX_SC_R_M4_0_I2C,
IMX_SC_R_ELCDIF_PLL,
IMX_SC_R_AUDIO_PLL_0,
IMX_SC_R_PI_0,
+ IMX_SC_R_PI_0_PWM_0,
+ IMX_SC_R_PI_0_I2C_0,
IMX_SC_R_PI_0_PLL,
IMX_SC_R_MIPI_0,
IMX_SC_R_MIPI_0_PWM_0,
diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c
index 40a2efb1329b..73efd7c460e8 100644
--- a/drivers/clk/imx/clk-imx8qxp.c
+++ b/drivers/clk/imx/clk-imx8qxp.c
@@ -91,6 +91,11 @@ static const char * const pi_pll0_sels[] = {
"clk_dummy",
};
+static inline bool clk_on_imx8dxl(struct device_node *node)
+{
+ return of_device_is_compatible(node, "fsl,imx8dxl-clk") != 0;
+}
+
static int imx8qxp_clk_probe(struct platform_device *pdev)
{
struct device_node *ccm_node = pdev->dev.of_node;
@@ -116,7 +121,6 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
imx_clk_scu("pwm5_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER);
imx_clk_scu("pwm6_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER);
imx_clk_scu("pwm7_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER);
- imx_clk_scu("gpt0_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER);
imx_clk_scu("gpt1_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER);
imx_clk_scu("gpt2_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER);
imx_clk_scu("gpt3_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER);
@@ -148,10 +152,10 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
imx_clk_scu("adc0_clk", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER);
imx_clk_scu("adc1_clk", IMX_SC_R_ADC_1, IMX_SC_PM_CLK_PER);
imx_clk_scu("pwm_clk", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("elcdif_pll", IMX_SC_R_ELCDIF_PLL, IMX_SC_PM_CLK_PLL);
imx_clk_scu2("lcd_clk", lcd_sels, ARRAY_SIZE(lcd_sels), IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER);
imx_clk_scu2("lcd_pxl_clk", lcd_pxl_sels, ARRAY_SIZE(lcd_pxl_sels), IMX_SC_R_LCD_0, IMX_SC_PM_CLK_MISC0);
imx_clk_scu("lcd_pxl_bypass_div_clk", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_BYPASS);
- imx_clk_scu("elcdif_pll", IMX_SC_R_ELCDIF_PLL, IMX_SC_PM_CLK_PLL);
/* Audio SS */
imx_clk_scu("audio_pll0_clk", IMX_SC_R_AUDIO_PLL_0, IMX_SC_PM_CLK_PLL);
@@ -170,13 +174,15 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
imx_clk_mux_gpr_scu("enet0_rgmii_txc_sel", enet0_rgmii_txc_sels, ARRAY_SIZE(enet0_rgmii_txc_sels), IMX_SC_R_ENET_0, IMX_SC_C_TXCLK);
imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS);
imx_clk_gate_gpr_scu("enet0_ref_50_clk", "clk_dummy", IMX_SC_R_ENET_0, IMX_SC_C_DISABLE_50, true);
- imx_clk_scu("enet0_rgmii_rx_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0);
+ if (!clk_on_imx8dxl(ccm_node)) {
+ imx_clk_scu("enet0_rgmii_rx_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu("enet1_rgmii_rx_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0);
+ }
imx_clk_scu("enet1_root_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER);
imx_clk_divider_gpr_scu("enet1_ref_div", "enet1_root_clk", IMX_SC_R_ENET_1, IMX_SC_C_CLKDIV);
imx_clk_mux_gpr_scu("enet1_rgmii_txc_sel", enet1_rgmii_txc_sels, ARRAY_SIZE(enet1_rgmii_txc_sels), IMX_SC_R_ENET_1, IMX_SC_C_TXCLK);
imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS);
imx_clk_gate_gpr_scu("enet1_ref_50_clk", "clk_dummy", IMX_SC_R_ENET_1, IMX_SC_C_DISABLE_50, true);
- imx_clk_scu("enet1_rgmii_rx_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0);
imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS);
imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER);
imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER);
@@ -297,6 +303,7 @@ static const struct of_device_id imx8qxp_match[] = {
{ .compatible = "fsl,scu-clk", },
{ .compatible = "fsl,imx8qxp-clk", &imx_clk_scu_rsrc_imx8qxp, },
{ .compatible = "fsl,imx8qm-clk", &imx_clk_scu_rsrc_imx8qm, },
+ { .compatible = "fsl,imx8dxl-clk", &imx_clk_scu_rsrc_imx8dxl, },
{ /* sentinel */ }
};
diff --git a/drivers/clk/imx/clk-imx8ulp.c b/drivers/clk/imx/clk-imx8ulp.c
new file mode 100644
index 000000000000..909d121ec0a6
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8ulp.c
@@ -0,0 +1,577 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 NXP
+ */
+
+#include <dt-bindings/clock/imx8ulp-clock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+static const char * const pll_pre_sels[] = { "sosc", "frosc", };
+static const char * const a35_sels[] = { "frosc", "spll2", "sosc", "lvds", };
+static const char * const nic_sels[] = { "frosc", "spll3_pfd0", "sosc", "lvds", };
+static const char * const pcc3_periph_bus_sels[] = { "dummy", "lposc", "sosc_div2",
+ "frosc_div2", "xbar_divbus", "spll3_pfd1_div1",
+ "spll3_pfd0_div2", "spll3_pfd0_div1", };
+static const char * const pcc4_periph_bus_sels[] = { "dummy", "dummy", "lposc",
+ "sosc_div2", "frosc_div2", "xbar_divbus",
+ "spll3_vcodiv", "spll3_pfd0_div1", };
+static const char * const pcc4_periph_plat_sels[] = { "dummy", "sosc_div1", "frosc_div1",
+ "spll3_pfd3_div2", "spll3_pfd3_div1",
+ "spll3_pfd2_div2", "spll3_pfd2_div1",
+ "spll3_pfd1_div2", };
+static const char * const pcc5_periph_bus_sels[] = { "dummy", "dummy", "lposc",
+ "sosc_div2", "frosc_div2", "lpav_bus_clk",
+ "pll4_vcodiv", "pll4_pfd3_div1", };
+static const char * const pcc5_periph_plat_sels[] = { "dummy", "pll4_pfd3_div2", "pll4_pfd2_div2",
+ "pll4_pfd2_div1", "pll4_pfd1_div2",
+ "pll4_pfd1_div1", "pll4_pfd0_div2",
+ "pll4_pfd0_div1", };
+static const char * const hifi_sels[] = { "frosc", "pll4", "pll4_pfd0", "sosc",
+ "lvds", "dummy", "dummy", "dummy", };
+static const char * const ddr_sels[] = { "frosc", "pll4_pfd1", "sosc", "lvds",
+ "pll4", "pll4", "pll4", "pll4", };
+static const char * const lpav_sels[] = { "frosc", "pll4_pfd1", "sosc", "lvds", };
+static const char * const sai45_sels[] = { "spll3_pfd1_div1", "aud_clk1", "aud_clk2", "sosc", };
+static const char * const sai67_sels[] = { "spll1_pfd2_div", "spll3_pfd1_div1", "aud_clk0", "aud_clk1", "aud_clk2", "sosc", "dummy", "dummy", };
+static const char * const aud_clk1_sels[] = { "ext_aud_mclk2", "sai4_rx_bclk", "sai4_tx_bclk", "sai5_rx_bclk", "sai5_tx_bclk", "dummy", "dummy", "dummy", };
+static const char * const aud_clk2_sels[] = { "ext_aud_mclk3", "sai6_rx_bclk", "sai6_tx_bclk", "sai7_rx_bclk", "sai7_tx_bclk", "spdif_rx", "dummy", "dummy", };
+static const char * const enet_ts_sels[] = { "ext_rmii_clk", "ext_ts_clk", "rosc", "ext_aud_mclk", "sosc", "dummy", "dummy", "dummy"};
+static const char * const xbar_divbus[] = { "xbar_divbus" };
+static const char * const nic_per_divplat[] = { "nic_per_divplat" };
+static const char * const lpav_axi_div[] = { "lpav_axi_div" };
+static const char * const lpav_bus_div[] = { "lpav_bus_div" };
+
+struct pcc_reset_dev {
+ void __iomem *base;
+ struct reset_controller_dev rcdev;
+ const u32 *resets;
+ spinlock_t *lock;
+};
+
+#define PCC_SW_RST BIT(28)
+#define to_pcc_reset_dev(_rcdev) container_of(_rcdev, struct pcc_reset_dev, rcdev)
+
+static const u32 pcc3_resets[] = {
+ 0xa8, 0xac, 0xc8, 0xcc, 0xd0,
+ 0xd4, 0xd8, 0xdc, 0xe0, 0xe4,
+ 0xe8, 0xec, 0xf0
+};
+
+static const u32 pcc4_resets[] = {
+ 0x4, 0x8, 0xc, 0x10, 0x14,
+ 0x18, 0x1c, 0x20, 0x24, 0x34,
+ 0x38, 0x3c, 0x40, 0x44, 0x48,
+ 0x4c, 0x54
+};
+
+static const u32 pcc5_resets[] = {
+ 0xa0, 0xa4, 0xa8, 0xac, 0xb0,
+ 0xb4, 0xbc, 0xc0, 0xc8, 0xcc,
+ 0xd0, 0xf0, 0xf4, 0xf8
+};
+
+static int imx8ulp_pcc_assert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ struct pcc_reset_dev *pcc_reset = to_pcc_reset_dev(rcdev);
+ u8 offset = pcc_reset->resets[id];
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(pcc_reset->lock, flags);
+
+ val = readl(pcc_reset->base + offset);
+ val &= ~PCC_SW_RST;
+ writel(val, pcc_reset->base + offset);
+
+ spin_unlock_irqrestore(pcc_reset->lock, flags);
+
+ return 0;
+}
+
+static int imx8ulp_pcc_deassert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ struct pcc_reset_dev *pcc_reset = to_pcc_reset_dev(rcdev);
+ u8 offset = pcc_reset->resets[id];
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(pcc_reset->lock, flags);
+
+ val = readl(pcc_reset->base + offset);
+ val |= PCC_SW_RST;
+ writel(val, pcc_reset->base + offset);
+
+ spin_unlock_irqrestore(pcc_reset->lock, flags);
+
+ return 0;
+}
+
+static const struct reset_control_ops imx8ulp_pcc_reset_ops = {
+ .assert = imx8ulp_pcc_assert,
+ .deassert = imx8ulp_pcc_deassert,
+};
+
+static int imx8ulp_pcc_reset_init(struct platform_device *pdev, void __iomem *base,
+ const u32 *resets, unsigned int nr_resets)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct pcc_reset_dev *pcc_reset;
+
+ pcc_reset = devm_kzalloc(dev, sizeof(*pcc_reset), GFP_KERNEL);
+ if (!pcc_reset)
+ return -ENOMEM;
+
+ pcc_reset->base = base;
+ pcc_reset->lock = &imx_ccm_lock;
+ pcc_reset->resets = resets;
+ pcc_reset->rcdev.owner = THIS_MODULE;
+ pcc_reset->rcdev.nr_resets = nr_resets;
+ pcc_reset->rcdev.ops = &imx8ulp_pcc_reset_ops;
+ pcc_reset->rcdev.of_node = np;
+
+ return devm_reset_controller_register(dev, &pcc_reset->rcdev);
+}
+
+static int imx8ulp_clk_cgc1_init(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct clk_hw_onecell_data *clk_data;
+ struct clk_hw **clks;
+ void __iomem *base;
+
+ clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_CGC1_END),
+ GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->num = IMX8ULP_CLK_CGC1_END;
+ clks = clk_data->hws;
+
+ clks[IMX8ULP_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
+
+ clks[IMX8ULP_CLK_FROSC] = imx_obtain_fixed_clk_hw(np, "frosc");
+ clks[IMX8ULP_CLK_LPOSC] = imx_obtain_fixed_clk_hw(np, "lposc");
+ clks[IMX8ULP_CLK_ROSC] = imx_obtain_fixed_clk_hw(np, "rosc");
+ clks[IMX8ULP_CLK_SOSC] = imx_obtain_fixed_clk_hw(np, "sosc");
+
+ /* CGC1 */
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks[IMX8ULP_CLK_SPLL2_PRE_SEL] = imx_clk_hw_mux_flags("spll2_pre_sel", base + 0x510, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE);
+ clks[IMX8ULP_CLK_SPLL3_PRE_SEL] = imx_clk_hw_mux_flags("spll3_pre_sel", base + 0x610, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE);
+
+ clks[IMX8ULP_CLK_SPLL2] = imx_clk_hw_pllv4(IMX_PLLV4_IMX8ULP, "spll2", "spll2_pre_sel", base + 0x500);
+ clks[IMX8ULP_CLK_SPLL3] = imx_clk_hw_pllv4(IMX_PLLV4_IMX8ULP, "spll3", "spll3_pre_sel", base + 0x600);
+ clks[IMX8ULP_CLK_SPLL3_VCODIV] = imx_clk_hw_divider("spll3_vcodiv", "spll3", base + 0x604, 0, 6);
+
+ clks[IMX8ULP_CLK_SPLL3_PFD0] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX8ULP, "spll3_pfd0", "spll3_vcodiv", base + 0x614, 0);
+ clks[IMX8ULP_CLK_SPLL3_PFD1] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX8ULP, "spll3_pfd1", "spll3_vcodiv", base + 0x614, 1);
+ clks[IMX8ULP_CLK_SPLL3_PFD2] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX8ULP, "spll3_pfd2", "spll3_vcodiv", base + 0x614, 2);
+ clks[IMX8ULP_CLK_SPLL3_PFD3] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX8ULP, "spll3_pfd3", "spll3_vcodiv", base + 0x614, 3);
+
+ clks[IMX8ULP_CLK_SPLL3_PFD0_DIV1_GATE] = imx_clk_hw_gate_dis("spll3_pfd0_div1_gate", "spll3_pfd0", base + 0x608, 7);
+ clks[IMX8ULP_CLK_SPLL3_PFD0_DIV2_GATE] = imx_clk_hw_gate_dis("spll3_pfd0_div2_gate", "spll3_pfd0", base + 0x608, 15);
+ clks[IMX8ULP_CLK_SPLL3_PFD1_DIV1_GATE] = imx_clk_hw_gate_dis("spll3_pfd1_div1_gate", "spll3_pfd1", base + 0x608, 23);
+ clks[IMX8ULP_CLK_SPLL3_PFD1_DIV2_GATE] = imx_clk_hw_gate_dis("spll3_pfd1_div2_gate", "spll3_pfd1", base + 0x608, 31);
+ clks[IMX8ULP_CLK_SPLL3_PFD2_DIV1_GATE] = imx_clk_hw_gate_dis("spll3_pfd2_div1_gate", "spll3_pfd2", base + 0x60c, 7);
+ clks[IMX8ULP_CLK_SPLL3_PFD2_DIV2_GATE] = imx_clk_hw_gate_dis("spll3_pfd2_div2_gate", "spll3_pfd2", base + 0x60c, 15);
+ clks[IMX8ULP_CLK_SPLL3_PFD3_DIV1_GATE] = imx_clk_hw_gate_dis("spll3_pfd3_div1_gate", "spll3_pfd3", base + 0x60c, 23);
+ clks[IMX8ULP_CLK_SPLL3_PFD3_DIV2_GATE] = imx_clk_hw_gate_dis("spll3_pfd3_div2_gate", "spll3_pfd3", base + 0x60c, 31);
+ clks[IMX8ULP_CLK_SPLL3_PFD0_DIV1] = imx_clk_hw_divider("spll3_pfd0_div1", "spll3_pfd0_div1_gate", base + 0x608, 0, 6);
+ clks[IMX8ULP_CLK_SPLL3_PFD0_DIV2] = imx_clk_hw_divider("spll3_pfd0_div2", "spll3_pfd0_div2_gate", base + 0x608, 8, 6);
+ clks[IMX8ULP_CLK_SPLL3_PFD1_DIV1] = imx_clk_hw_divider("spll3_pfd1_div1", "spll3_pfd1_div1_gate", base + 0x608, 16, 6);
+ clks[IMX8ULP_CLK_SPLL3_PFD1_DIV2] = imx_clk_hw_divider("spll3_pfd1_div2", "spll3_pfd1_div2_gate", base + 0x608, 24, 6);
+ clks[IMX8ULP_CLK_SPLL3_PFD2_DIV1] = imx_clk_hw_divider("spll3_pfd2_div1", "spll3_pfd2_div1_gate", base + 0x60c, 0, 6);
+ clks[IMX8ULP_CLK_SPLL3_PFD2_DIV2] = imx_clk_hw_divider("spll3_pfd2_div2", "spll3_pfd2_div2_gate", base + 0x60c, 8, 6);
+ clks[IMX8ULP_CLK_SPLL3_PFD3_DIV1] = imx_clk_hw_divider("spll3_pfd3_div1", "spll3_pfd3_div1_gate", base + 0x60c, 16, 6);
+ clks[IMX8ULP_CLK_SPLL3_PFD3_DIV2] = imx_clk_hw_divider("spll3_pfd3_div2", "spll3_pfd3_div2_gate", base + 0x60c, 24, 6);
+
+ clks[IMX8ULP_CLK_A35_SEL] = imx_clk_hw_mux2("a35_sel", base + 0x14, 28, 2, a35_sels, ARRAY_SIZE(a35_sels));
+ clks[IMX8ULP_CLK_A35_DIV] = imx_clk_hw_divider_flags("a35_div", "a35_sel", base + 0x14, 21, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+
+ clks[IMX8ULP_CLK_NIC_SEL] = imx_clk_hw_mux2("nic_sel", base + 0x34, 28, 2, nic_sels, ARRAY_SIZE(nic_sels));
+ clks[IMX8ULP_CLK_NIC_AD_DIVPLAT] = imx_clk_hw_divider_flags("nic_ad_divplat", "nic_sel", base + 0x34, 21, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+ clks[IMX8ULP_CLK_NIC_PER_DIVPLAT] = imx_clk_hw_divider_flags("nic_per_divplat", "nic_ad_divplat", base + 0x34, 14, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+ clks[IMX8ULP_CLK_XBAR_AD_DIVPLAT] = imx_clk_hw_divider_flags("xbar_ad_divplat", "nic_ad_divplat", base + 0x38, 14, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+ clks[IMX8ULP_CLK_XBAR_DIVBUS] = imx_clk_hw_divider_flags("xbar_divbus", "nic_ad_divplat", base + 0x38, 7, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+ clks[IMX8ULP_CLK_XBAR_AD_SLOW] = imx_clk_hw_divider_flags("xbar_ad_slow", "nic_ad_divplat", base + 0x38, 0, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+
+ clks[IMX8ULP_CLK_SOSC_DIV1_GATE] = imx_clk_hw_gate_dis("sosc_div1_gate", "sosc", base + 0x108, 7);
+ clks[IMX8ULP_CLK_SOSC_DIV2_GATE] = imx_clk_hw_gate_dis("sosc_div2_gate", "sosc", base + 0x108, 15);
+ clks[IMX8ULP_CLK_SOSC_DIV3_GATE] = imx_clk_hw_gate_dis("sosc_div3_gate", "sosc", base + 0x108, 23);
+ clks[IMX8ULP_CLK_SOSC_DIV1] = imx_clk_hw_divider("sosc_div1", "sosc_div1_gate", base + 0x108, 0, 6);
+ clks[IMX8ULP_CLK_SOSC_DIV2] = imx_clk_hw_divider("sosc_div2", "sosc_div2_gate", base + 0x108, 8, 6);
+ clks[IMX8ULP_CLK_SOSC_DIV3] = imx_clk_hw_divider("sosc_div3", "sosc_div3_gate", base + 0x108, 16, 6);
+
+ clks[IMX8ULP_CLK_FROSC_DIV1_GATE] = imx_clk_hw_gate_dis("frosc_div1_gate", "frosc", base + 0x208, 7);
+ clks[IMX8ULP_CLK_FROSC_DIV2_GATE] = imx_clk_hw_gate_dis("frosc_div2_gate", "frosc", base + 0x208, 15);
+ clks[IMX8ULP_CLK_FROSC_DIV3_GATE] = imx_clk_hw_gate_dis("frosc_div3_gate", "frosc", base + 0x208, 23);
+ clks[IMX8ULP_CLK_FROSC_DIV1] = imx_clk_hw_divider("frosc_div1", "frosc_div1_gate", base + 0x208, 0, 6);
+ clks[IMX8ULP_CLK_FROSC_DIV2] = imx_clk_hw_divider("frosc_div2", "frosc_div2_gate", base + 0x208, 8, 6);
+ clks[IMX8ULP_CLK_FROSC_DIV3] = imx_clk_hw_divider("frosc_div3", "frosc_div3_gate", base + 0x208, 16, 6);
+ clks[IMX8ULP_CLK_AUD_CLK1] = imx_clk_hw_mux2("aud_clk1", base + 0x900, 0, 3, aud_clk1_sels, ARRAY_SIZE(aud_clk1_sels));
+ clks[IMX8ULP_CLK_SAI4_SEL] = imx_clk_hw_mux2("sai4_sel", base + 0x904, 0, 2, sai45_sels, ARRAY_SIZE(sai45_sels));
+ clks[IMX8ULP_CLK_SAI5_SEL] = imx_clk_hw_mux2("sai5_sel", base + 0x904, 8, 2, sai45_sels, ARRAY_SIZE(sai45_sels));
+ clks[IMX8ULP_CLK_ENET_TS_SEL] = imx_clk_hw_mux2("enet_ts", base + 0x700, 24, 3, enet_ts_sels, ARRAY_SIZE(enet_ts_sels));
+
+ imx_check_clk_hws(clks, clk_data->num);
+
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
+}
+
+static int imx8ulp_clk_cgc2_init(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct clk_hw_onecell_data *clk_data;
+ struct clk_hw **clks;
+ void __iomem *base;
+
+ clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_CGC2_END),
+ GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->num = IMX8ULP_CLK_CGC2_END;
+ clks = clk_data->hws;
+
+ /* CGC2 */
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks[IMX8ULP_CLK_PLL4_PRE_SEL] = imx_clk_hw_mux_flags("pll4_pre_sel", base + 0x610, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE);
+
+ clks[IMX8ULP_CLK_PLL4] = imx_clk_hw_pllv4(IMX_PLLV4_IMX8ULP, "pll4", "pll4_pre_sel", base + 0x600);
+ clks[IMX8ULP_CLK_PLL4_VCODIV] = imx_clk_hw_divider("pll4_vcodiv", "pll4", base + 0x604, 0, 6);
+
+ clks[IMX8ULP_CLK_HIFI_SEL] = imx_clk_hw_mux_flags("hifi_sel", base + 0x14, 28, 3, hifi_sels, ARRAY_SIZE(hifi_sels), CLK_SET_PARENT_GATE);
+ clks[IMX8ULP_CLK_HIFI_DIVCORE] = imx_clk_hw_divider("hifi_core_div", "hifi_sel", base + 0x14, 21, 6);
+ clks[IMX8ULP_CLK_HIFI_DIVPLAT] = imx_clk_hw_divider("hifi_plat_div", "hifi_core_div", base + 0x14, 14, 6);
+
+ clks[IMX8ULP_CLK_DDR_SEL] = imx_clk_hw_mux_flags("ddr_sel", base + 0x40, 28, 3, ddr_sels, ARRAY_SIZE(ddr_sels), CLK_GET_RATE_NOCACHE);
+ clks[IMX8ULP_CLK_DDR_DIV] = imx_clk_hw_divider_flags("ddr_div", "ddr_sel", base + 0x40, 21, 6, CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE);
+ clks[IMX8ULP_CLK_LPAV_AXI_SEL] = imx_clk_hw_mux_flags("lpav_sel", base + 0x3c, 28, 2, lpav_sels, ARRAY_SIZE(lpav_sels), CLK_SET_PARENT_GATE);
+ clks[IMX8ULP_CLK_LPAV_AXI_DIV] = imx_clk_hw_divider_flags("lpav_axi_div", "lpav_sel", base + 0x3c, 21, 6, CLK_IS_CRITICAL);
+ clks[IMX8ULP_CLK_LPAV_AHB_DIV] = imx_clk_hw_divider_flags("lpav_ahb_div", "lpav_axi_div", base + 0x3c, 14, 6, CLK_IS_CRITICAL);
+ clks[IMX8ULP_CLK_LPAV_BUS_DIV] = imx_clk_hw_divider_flags("lpav_bus_div", "lpav_axi_div", base + 0x3c, 7, 6, CLK_IS_CRITICAL);
+
+ clks[IMX8ULP_CLK_PLL4_PFD0] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX8ULP, "pll4_pfd0", "pll4_vcodiv", base + 0x614, 0);
+ clks[IMX8ULP_CLK_PLL4_PFD1] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX8ULP, "pll4_pfd1", "pll4_vcodiv", base + 0x614, 1);
+ clks[IMX8ULP_CLK_PLL4_PFD2] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX8ULP, "pll4_pfd2", "pll4_vcodiv", base + 0x614, 2);
+ clks[IMX8ULP_CLK_PLL4_PFD3] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX8ULP, "pll4_pfd3", "pll4_vcodiv", base + 0x614, 3);
+
+ clks[IMX8ULP_CLK_PLL4_PFD0_DIV1_GATE] = imx_clk_hw_gate_dis("pll4_pfd0_div1_gate", "pll4_pfd0", base + 0x608, 7);
+ clks[IMX8ULP_CLK_PLL4_PFD0_DIV2_GATE] = imx_clk_hw_gate_dis("pll4_pfd0_div2_gate", "pll4_pfd0", base + 0x608, 15);
+ clks[IMX8ULP_CLK_PLL4_PFD1_DIV1_GATE] = imx_clk_hw_gate_dis("pll4_pfd1_div1_gate", "pll4_pfd1", base + 0x608, 23);
+ clks[IMX8ULP_CLK_PLL4_PFD1_DIV2_GATE] = imx_clk_hw_gate_dis("pll4_pfd1_div2_gate", "pll4_pfd1", base + 0x608, 31);
+ clks[IMX8ULP_CLK_PLL4_PFD2_DIV1_GATE] = imx_clk_hw_gate_dis("pll4_pfd2_div1_gate", "pll4_pfd2", base + 0x60c, 7);
+ clks[IMX8ULP_CLK_PLL4_PFD2_DIV2_GATE] = imx_clk_hw_gate_dis("pll4_pfd2_div2_gate", "pll4_pfd2", base + 0x60c, 15);
+ clks[IMX8ULP_CLK_PLL4_PFD3_DIV1_GATE] = imx_clk_hw_gate_dis("pll4_pfd3_div1_gate", "pll4_pfd3", base + 0x60c, 23);
+ clks[IMX8ULP_CLK_PLL4_PFD3_DIV2_GATE] = imx_clk_hw_gate_dis("pll4_pfd3_div2_gate", "pll4_pfd3", base + 0x60c, 31);
+ clks[IMX8ULP_CLK_PLL4_PFD0_DIV1] = imx_clk_hw_divider_closest("pll4_pfd0_div1", "pll4_pfd0_div1_gate", base + 0x608, 0, 6);
+ clks[IMX8ULP_CLK_PLL4_PFD0_DIV2] = imx_clk_hw_divider_closest("pll4_pfd0_div2", "pll4_pfd0_div2_gate", base + 0x608, 8, 6);
+ clks[IMX8ULP_CLK_PLL4_PFD1_DIV1] = imx_clk_hw_divider_closest("pll4_pfd1_div1", "pll4_pfd1_div1_gate", base + 0x608, 16, 6);
+ clks[IMX8ULP_CLK_PLL4_PFD1_DIV2] = imx_clk_hw_divider_closest("pll4_pfd1_div2", "pll4_pfd1_div2_gate", base + 0x608, 24, 6);
+ clks[IMX8ULP_CLK_PLL4_PFD2_DIV1] = imx_clk_hw_divider_closest("pll4_pfd2_div1", "pll4_pfd2_div1_gate", base + 0x60c, 0, 6);
+ clks[IMX8ULP_CLK_PLL4_PFD2_DIV2] = imx_clk_hw_divider_closest("pll4_pfd2_div2", "pll4_pfd2_div2_gate", base + 0x60c, 8, 6);
+ clks[IMX8ULP_CLK_PLL4_PFD3_DIV1] = imx_clk_hw_divider_closest("pll4_pfd3_div1", "pll4_pfd3_div1_gate", base + 0x60c, 16, 6);
+ clks[IMX8ULP_CLK_PLL4_PFD3_DIV2] = imx_clk_hw_divider_closest("pll4_pfd3_div2", "pll4_pfd3_div2_gate", base + 0x60c, 24, 6);
+
+ clks[IMX8ULP_CLK_CGC2_SOSC_DIV1_GATE] = imx_clk_hw_gate_dis("cgc2_sosc_div1_gate", "sosc", base + 0x108, 7);
+ clks[IMX8ULP_CLK_CGC2_SOSC_DIV2_GATE] = imx_clk_hw_gate_dis("cgc2_sosc_div2_gate", "sosc", base + 0x108, 15);
+ clks[IMX8ULP_CLK_CGC2_SOSC_DIV3_GATE] = imx_clk_hw_gate_dis("cgc2_sosc_div3_gate", "sosc", base + 0x108, 23);
+ clks[IMX8ULP_CLK_CGC2_SOSC_DIV1] = imx_clk_hw_divider("cgc2_sosc_div1", "cgc2_sosc_div1_gate", base + 0x108, 0, 6);
+ clks[IMX8ULP_CLK_CGC2_SOSC_DIV2] = imx_clk_hw_divider("cgc2_sosc_div2", "cgc2_sosc_div2_gate", base + 0x108, 8, 6);
+ clks[IMX8ULP_CLK_CGC2_SOSC_DIV3] = imx_clk_hw_divider("cgc2_sosc_div3", "cgc2_sosc_div3_gate", base + 0x108, 16, 6);
+
+ clks[IMX8ULP_CLK_CGC2_FROSC_DIV1_GATE] = imx_clk_hw_gate_dis("cgc2_frosc_div1_gate", "frosc", base + 0x208, 7);
+ clks[IMX8ULP_CLK_CGC2_FROSC_DIV2_GATE] = imx_clk_hw_gate_dis("cgc2_frosc_div2_gate", "frosc", base + 0x208, 15);
+ clks[IMX8ULP_CLK_CGC2_FROSC_DIV3_GATE] = imx_clk_hw_gate_dis("cgc2_frosc_div3_gate", "frosc", base + 0x208, 23);
+ clks[IMX8ULP_CLK_CGC2_FROSC_DIV1] = imx_clk_hw_divider("cgc2_frosc_div1", "cgc2_frosc_div1_gate", base + 0x208, 0, 6);
+ clks[IMX8ULP_CLK_CGC2_FROSC_DIV2] = imx_clk_hw_divider("cgc2_frosc_div2", "cgc2_frosc_div2_gate", base + 0x208, 8, 6);
+ clks[IMX8ULP_CLK_CGC2_FROSC_DIV3] = imx_clk_hw_divider("cgc2_frosc_div3", "cgc2_frosc_div3_gate", base + 0x208, 16, 6);
+ clks[IMX8ULP_CLK_AUD_CLK2] = imx_clk_hw_mux2("aud_clk2", base + 0x900, 0, 3, aud_clk2_sels, ARRAY_SIZE(aud_clk2_sels));
+ clks[IMX8ULP_CLK_SAI6_SEL] = imx_clk_hw_mux2("sai6_sel", base + 0x904, 0, 3, sai67_sels, ARRAY_SIZE(sai67_sels));
+ clks[IMX8ULP_CLK_SAI7_SEL] = imx_clk_hw_mux2("sai7_sel", base + 0x904, 8, 3, sai67_sels, ARRAY_SIZE(sai67_sels));
+ clks[IMX8ULP_CLK_SPDIF_SEL] = imx_clk_hw_mux2("spdif_sel", base + 0x910, 0, 3, sai67_sels, ARRAY_SIZE(sai67_sels));
+ clks[IMX8ULP_CLK_DSI_PHY_REF] = imx_clk_hw_fixed("dsi_phy_ref", 24000000);
+
+ imx_check_clk_hws(clks, clk_data->num);
+
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
+}
+
+static int imx8ulp_clk_pcc3_init(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct clk_hw_onecell_data *clk_data;
+ struct clk_hw **clks;
+ void __iomem *base;
+ int ret;
+
+ clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_PCC3_END),
+ GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->num = IMX8ULP_CLK_PCC3_END;
+ clks = clk_data->hws;
+
+ /* PCC3 */
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks[IMX8ULP_CLK_WDOG3] = imx8ulp_clk_hw_composite("wdog3", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xa8, 1);
+ clks[IMX8ULP_CLK_WDOG4] = imx8ulp_clk_hw_composite("wdog4", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xac, 1);
+ clks[IMX8ULP_CLK_LPIT1] = imx8ulp_clk_hw_composite("lpit1", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xc8, 1);
+ clks[IMX8ULP_CLK_TPM4] = imx8ulp_clk_hw_composite("tpm4", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xcc, 1);
+ clks[IMX8ULP_CLK_FLEXIO1] = imx8ulp_clk_hw_composite("flexio1", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xd4, 1);
+ clks[IMX8ULP_CLK_I3C2] = imx8ulp_clk_hw_composite("i3c2", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xd8, 1);
+ clks[IMX8ULP_CLK_LPI2C4] = imx8ulp_clk_hw_composite("lpi2c4", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xdc, 1);
+ clks[IMX8ULP_CLK_LPI2C5] = imx8ulp_clk_hw_composite("lpi2c5", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xe0, 1);
+ clks[IMX8ULP_CLK_LPUART4] = imx8ulp_clk_hw_composite("lpuart4", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xe4, 1);
+ clks[IMX8ULP_CLK_LPUART5] = imx8ulp_clk_hw_composite("lpuart5", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xe8, 1);
+ clks[IMX8ULP_CLK_LPSPI4] = imx8ulp_clk_hw_composite("lpspi4", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xec, 1);
+ clks[IMX8ULP_CLK_LPSPI5] = imx8ulp_clk_hw_composite("lpspi5", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xf0, 1);
+
+ clks[IMX8ULP_CLK_DMA1_MP] = imx_clk_hw_gate("pcc_dma1_mp", "xbar_ad_divplat", base + 0x4, 30);
+ clks[IMX8ULP_CLK_DMA1_CH0] = imx_clk_hw_gate("pcc_dma1_ch0", "xbar_ad_divplat", base + 0x8, 30);
+ clks[IMX8ULP_CLK_DMA1_CH1] = imx_clk_hw_gate("pcc_dma1_ch1", "xbar_ad_divplat", base + 0xc, 30);
+ clks[IMX8ULP_CLK_DMA1_CH2] = imx_clk_hw_gate("pcc_dma1_ch2", "xbar_ad_divplat", base + 0x10, 30);
+ clks[IMX8ULP_CLK_DMA1_CH3] = imx_clk_hw_gate("pcc_dma1_ch3", "xbar_ad_divplat", base + 0x14, 30);
+ clks[IMX8ULP_CLK_DMA1_CH4] = imx_clk_hw_gate("pcc_dma1_ch4", "xbar_ad_divplat", base + 0x18, 30);
+ clks[IMX8ULP_CLK_DMA1_CH5] = imx_clk_hw_gate("pcc_dma1_ch5", "xbar_ad_divplat", base + 0x1c, 30);
+ clks[IMX8ULP_CLK_DMA1_CH6] = imx_clk_hw_gate("pcc_dma1_ch6", "xbar_ad_divplat", base + 0x20, 30);
+ clks[IMX8ULP_CLK_DMA1_CH7] = imx_clk_hw_gate("pcc_dma1_ch7", "xbar_ad_divplat", base + 0x24, 30);
+ clks[IMX8ULP_CLK_DMA1_CH8] = imx_clk_hw_gate("pcc_dma1_ch8", "xbar_ad_divplat", base + 0x28, 30);
+ clks[IMX8ULP_CLK_DMA1_CH9] = imx_clk_hw_gate("pcc_dma1_ch9", "xbar_ad_divplat", base + 0x2c, 30);
+ clks[IMX8ULP_CLK_DMA1_CH10] = imx_clk_hw_gate("pcc_dma1_ch10", "xbar_ad_divplat", base + 0x30, 30);
+ clks[IMX8ULP_CLK_DMA1_CH11] = imx_clk_hw_gate("pcc_dma1_ch11", "xbar_ad_divplat", base + 0x34, 30);
+ clks[IMX8ULP_CLK_DMA1_CH12] = imx_clk_hw_gate("pcc_dma1_ch12", "xbar_ad_divplat", base + 0x38, 30);
+ clks[IMX8ULP_CLK_DMA1_CH13] = imx_clk_hw_gate("pcc_dma1_ch13", "xbar_ad_divplat", base + 0x3c, 30);
+ clks[IMX8ULP_CLK_DMA1_CH14] = imx_clk_hw_gate("pcc_dma1_ch14", "xbar_ad_divplat", base + 0x40, 30);
+ clks[IMX8ULP_CLK_DMA1_CH15] = imx_clk_hw_gate("pcc_dma1_ch15", "xbar_ad_divplat", base + 0x44, 30);
+ clks[IMX8ULP_CLK_DMA1_CH16] = imx_clk_hw_gate("pcc_dma1_ch16", "xbar_ad_divplat", base + 0x48, 30);
+ clks[IMX8ULP_CLK_DMA1_CH17] = imx_clk_hw_gate("pcc_dma1_ch17", "xbar_ad_divplat", base + 0x4c, 30);
+ clks[IMX8ULP_CLK_DMA1_CH18] = imx_clk_hw_gate("pcc_dma1_ch18", "xbar_ad_divplat", base + 0x50, 30);
+ clks[IMX8ULP_CLK_DMA1_CH19] = imx_clk_hw_gate("pcc_dma1_ch19", "xbar_ad_divplat", base + 0x54, 30);
+ clks[IMX8ULP_CLK_DMA1_CH20] = imx_clk_hw_gate("pcc_dma1_ch20", "xbar_ad_divplat", base + 0x58, 30);
+ clks[IMX8ULP_CLK_DMA1_CH21] = imx_clk_hw_gate("pcc_dma1_ch21", "xbar_ad_divplat", base + 0x5c, 30);
+ clks[IMX8ULP_CLK_DMA1_CH22] = imx_clk_hw_gate("pcc_dma1_ch22", "xbar_ad_divplat", base + 0x60, 30);
+ clks[IMX8ULP_CLK_DMA1_CH23] = imx_clk_hw_gate("pcc_dma1_ch23", "xbar_ad_divplat", base + 0x64, 30);
+ clks[IMX8ULP_CLK_DMA1_CH24] = imx_clk_hw_gate("pcc_dma1_ch24", "xbar_ad_divplat", base + 0x68, 30);
+ clks[IMX8ULP_CLK_DMA1_CH25] = imx_clk_hw_gate("pcc_dma1_ch25", "xbar_ad_divplat", base + 0x6c, 30);
+ clks[IMX8ULP_CLK_DMA1_CH26] = imx_clk_hw_gate("pcc_dma1_ch26", "xbar_ad_divplat", base + 0x70, 30);
+ clks[IMX8ULP_CLK_DMA1_CH27] = imx_clk_hw_gate("pcc_dma1_ch27", "xbar_ad_divplat", base + 0x74, 30);
+ clks[IMX8ULP_CLK_DMA1_CH28] = imx_clk_hw_gate("pcc_dma1_ch28", "xbar_ad_divplat", base + 0x78, 30);
+ clks[IMX8ULP_CLK_DMA1_CH29] = imx_clk_hw_gate("pcc_dma1_ch29", "xbar_ad_divplat", base + 0x7c, 30);
+ clks[IMX8ULP_CLK_DMA1_CH30] = imx_clk_hw_gate("pcc_dma1_ch30", "xbar_ad_divplat", base + 0x80, 30);
+ clks[IMX8ULP_CLK_DMA1_CH31] = imx_clk_hw_gate("pcc_dma1_ch31", "xbar_ad_divplat", base + 0x84, 30);
+ clks[IMX8ULP_CLK_MU0_B] = imx_clk_hw_gate_flags("mu0_b", "xbar_ad_divplat", base + 0x88, 30, CLK_IS_CRITICAL);
+ clks[IMX8ULP_CLK_MU3_A] = imx_clk_hw_gate("mu3_a", "xbar_ad_divplat", base + 0x8c, 30);
+ clks[IMX8ULP_CLK_TPM5] = imx_clk_hw_gate_flags("tpm5", "sosc_div2", base + 0xd0, 30, CLK_IS_CRITICAL);
+
+ imx_check_clk_hws(clks, clk_data->num);
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
+ if (ret)
+ return ret;
+
+ imx_register_uart_clocks(1);
+
+ /* register the pcc3 reset controller */
+ return imx8ulp_pcc_reset_init(pdev, base, pcc3_resets, ARRAY_SIZE(pcc3_resets));
+}
+
+static int imx8ulp_clk_pcc4_init(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct clk_hw_onecell_data *clk_data;
+ struct clk_hw **clks;
+ void __iomem *base;
+ int ret;
+
+ clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_PCC4_END),
+ GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->num = IMX8ULP_CLK_PCC4_END;
+ clks = clk_data->hws;
+
+ /* PCC4 */
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks[IMX8ULP_CLK_FLEXSPI2] = imx8ulp_clk_hw_composite("flexspi2", pcc4_periph_plat_sels, ARRAY_SIZE(pcc4_periph_plat_sels), true, true, true, base + 0x4, 1);
+ clks[IMX8ULP_CLK_TPM6] = imx8ulp_clk_hw_composite("tpm6", pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), true, true, true, base + 0x8, 1);
+ clks[IMX8ULP_CLK_TPM7] = imx8ulp_clk_hw_composite("tpm7", pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), true, true, true, base + 0xc, 1);
+ clks[IMX8ULP_CLK_LPI2C6] = imx8ulp_clk_hw_composite("lpi2c6", pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), true, true, true, base + 0x10, 1);
+ clks[IMX8ULP_CLK_LPI2C7] = imx8ulp_clk_hw_composite("lpi2c7", pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), true, true, true, base + 0x14, 1);
+ clks[IMX8ULP_CLK_LPUART6] = imx8ulp_clk_hw_composite("lpuart6", pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), true, true, true, base + 0x18, 1);
+ clks[IMX8ULP_CLK_LPUART7] = imx8ulp_clk_hw_composite("lpuart7", pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), true, true, true, base + 0x1c, 1);
+ clks[IMX8ULP_CLK_SAI4] = imx8ulp_clk_hw_composite("sai4", xbar_divbus, 1, false, false, true, base + 0x20, 1); /* sai ipg, NOT from sai sel */
+ clks[IMX8ULP_CLK_SAI5] = imx8ulp_clk_hw_composite("sai5", xbar_divbus, 1, false, false, true, base + 0x24, 1); /* sai ipg */
+ clks[IMX8ULP_CLK_PCTLE] = imx_clk_hw_gate("pctle", "xbar_divbus", base + 0x28, 30);
+ clks[IMX8ULP_CLK_PCTLF] = imx_clk_hw_gate("pctlf", "xbar_divbus", base + 0x2c, 30);
+ clks[IMX8ULP_CLK_USDHC0] = imx8ulp_clk_hw_composite("usdhc0", pcc4_periph_plat_sels, ARRAY_SIZE(pcc4_periph_plat_sels), true, false, true, base + 0x34, 1);
+ clks[IMX8ULP_CLK_USDHC1] = imx8ulp_clk_hw_composite("usdhc1", pcc4_periph_plat_sels, ARRAY_SIZE(pcc4_periph_plat_sels), true, false, true, base + 0x38, 1);
+ clks[IMX8ULP_CLK_USDHC2] = imx8ulp_clk_hw_composite("usdhc2", pcc4_periph_plat_sels, ARRAY_SIZE(pcc4_periph_plat_sels), true, false, true, base + 0x3c, 1);
+ clks[IMX8ULP_CLK_USB0] = imx8ulp_clk_hw_composite("usb0", nic_per_divplat, 1, false, false, true, base + 0x40, 1);
+ clks[IMX8ULP_CLK_USB0_PHY] = imx8ulp_clk_hw_composite("usb0_phy", xbar_divbus, 1, false, false, true, base + 0x44, 1);
+ clks[IMX8ULP_CLK_USB1] = imx8ulp_clk_hw_composite("usb1", nic_per_divplat, 1, false, false, true, base + 0x48, 1);
+ clks[IMX8ULP_CLK_USB1_PHY] = imx8ulp_clk_hw_composite("usb1_phy", xbar_divbus, 1, false, false, true, base + 0x4c, 1);
+ clks[IMX8ULP_CLK_USB_XBAR] = imx_clk_hw_gate("usb_xbar", "xbar_divbus", base + 0x50, 30);
+ clks[IMX8ULP_CLK_ENET] = imx8ulp_clk_hw_composite("enet", nic_per_divplat, 1, false, false, true, base + 0x54, 1);
+ clks[IMX8ULP_CLK_RGPIOE] = imx_clk_hw_gate("rgpioe", "nic_per_divplat", base + 0x78, 30);
+ clks[IMX8ULP_CLK_RGPIOF] = imx_clk_hw_gate("rgpiof", "nic_per_divplat", base + 0x7c, 30);
+
+ imx_check_clk_hws(clks, clk_data->num);
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
+ if (ret)
+ return ret;
+
+ /* register the pcc4 reset controller */
+ return imx8ulp_pcc_reset_init(pdev, base, pcc4_resets, ARRAY_SIZE(pcc4_resets));
+
+}
+
+static int imx8ulp_clk_pcc5_init(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct clk_hw_onecell_data *clk_data;
+ struct clk_hw **clks;
+ void __iomem *base;
+ int ret;
+
+ clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_PCC5_END),
+ GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->num = IMX8ULP_CLK_PCC5_END;
+ clks = clk_data->hws;
+
+ /* PCC5 */
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks[IMX8ULP_CLK_DMA2_MP] = imx_clk_hw_gate("pcc_dma2_mp", "lpav_axi_div", base + 0x0, 30);
+ clks[IMX8ULP_CLK_DMA2_CH0] = imx_clk_hw_gate("pcc_dma2_ch0", "lpav_axi_div", base + 0x4, 30);
+ clks[IMX8ULP_CLK_DMA2_CH1] = imx_clk_hw_gate("pcc_dma2_ch1", "lpav_axi_div", base + 0x8, 30);
+ clks[IMX8ULP_CLK_DMA2_CH2] = imx_clk_hw_gate("pcc_dma2_ch2", "lpav_axi_div", base + 0xc, 30);
+ clks[IMX8ULP_CLK_DMA2_CH3] = imx_clk_hw_gate("pcc_dma2_ch3", "lpav_axi_div", base + 0x10, 30);
+ clks[IMX8ULP_CLK_DMA2_CH4] = imx_clk_hw_gate("pcc_dma2_ch4", "lpav_axi_div", base + 0x14, 30);
+ clks[IMX8ULP_CLK_DMA2_CH5] = imx_clk_hw_gate("pcc_dma2_ch5", "lpav_axi_div", base + 0x18, 30);
+ clks[IMX8ULP_CLK_DMA2_CH6] = imx_clk_hw_gate("pcc_dma2_ch6", "lpav_axi_div", base + 0x1c, 30);
+ clks[IMX8ULP_CLK_DMA2_CH7] = imx_clk_hw_gate("pcc_dma2_ch7", "lpav_axi_div", base + 0x20, 30);
+ clks[IMX8ULP_CLK_DMA2_CH8] = imx_clk_hw_gate("pcc_dma2_ch8", "lpav_axi_div", base + 0x24, 30);
+ clks[IMX8ULP_CLK_DMA2_CH9] = imx_clk_hw_gate("pcc_dma2_ch9", "lpav_axi_div", base + 0x28, 30);
+ clks[IMX8ULP_CLK_DMA2_CH10] = imx_clk_hw_gate("pcc_dma2_ch10", "lpav_axi_div", base + 0x2c, 30);
+ clks[IMX8ULP_CLK_DMA2_CH11] = imx_clk_hw_gate("pcc_dma2_ch11", "lpav_axi_div", base + 0x30, 30);
+ clks[IMX8ULP_CLK_DMA2_CH12] = imx_clk_hw_gate("pcc_dma2_ch12", "lpav_axi_div", base + 0x34, 30);
+ clks[IMX8ULP_CLK_DMA2_CH13] = imx_clk_hw_gate("pcc_dma2_ch13", "lpav_axi_div", base + 0x38, 30);
+ clks[IMX8ULP_CLK_DMA2_CH14] = imx_clk_hw_gate("pcc_dma2_ch14", "lpav_axi_div", base + 0x3c, 30);
+ clks[IMX8ULP_CLK_DMA2_CH15] = imx_clk_hw_gate("pcc_dma2_ch15", "lpav_axi_div", base + 0x40, 30);
+ clks[IMX8ULP_CLK_DMA2_CH16] = imx_clk_hw_gate("pcc_dma2_ch16", "lpav_axi_div", base + 0x44, 30);
+ clks[IMX8ULP_CLK_DMA2_CH17] = imx_clk_hw_gate("pcc_dma2_ch17", "lpav_axi_div", base + 0x48, 30);
+ clks[IMX8ULP_CLK_DMA2_CH18] = imx_clk_hw_gate("pcc_dma2_ch18", "lpav_axi_div", base + 0x4c, 30);
+ clks[IMX8ULP_CLK_DMA2_CH19] = imx_clk_hw_gate("pcc_dma2_ch19", "lpav_axi_div", base + 0x50, 30);
+ clks[IMX8ULP_CLK_DMA2_CH20] = imx_clk_hw_gate("pcc_dma2_ch20", "lpav_axi_div", base + 0x54, 30);
+ clks[IMX8ULP_CLK_DMA2_CH21] = imx_clk_hw_gate("pcc_dma2_ch21", "lpav_axi_div", base + 0x58, 30);
+ clks[IMX8ULP_CLK_DMA2_CH22] = imx_clk_hw_gate("pcc_dma2_ch22", "lpav_axi_div", base + 0x5c, 30);
+ clks[IMX8ULP_CLK_DMA2_CH23] = imx_clk_hw_gate("pcc_dma2_ch23", "lpav_axi_div", base + 0x60, 30);
+ clks[IMX8ULP_CLK_DMA2_CH24] = imx_clk_hw_gate("pcc_dma2_ch24", "lpav_axi_div", base + 0x64, 30);
+ clks[IMX8ULP_CLK_DMA2_CH25] = imx_clk_hw_gate("pcc_dma2_ch25", "lpav_axi_div", base + 0x68, 30);
+ clks[IMX8ULP_CLK_DMA2_CH26] = imx_clk_hw_gate("pcc_dma2_ch26", "lpav_axi_div", base + 0x6c, 30);
+ clks[IMX8ULP_CLK_DMA2_CH27] = imx_clk_hw_gate("pcc_dma2_ch27", "lpav_axi_div", base + 0x70, 30);
+ clks[IMX8ULP_CLK_DMA2_CH28] = imx_clk_hw_gate("pcc_dma2_ch28", "lpav_axi_div", base + 0x74, 30);
+ clks[IMX8ULP_CLK_DMA2_CH29] = imx_clk_hw_gate("pcc_dma2_ch29", "lpav_axi_div", base + 0x78, 30);
+ clks[IMX8ULP_CLK_DMA2_CH30] = imx_clk_hw_gate("pcc_dma2_ch30", "lpav_axi_div", base + 0x7c, 30);
+ clks[IMX8ULP_CLK_DMA2_CH31] = imx_clk_hw_gate("pcc_dma2_ch31", "lpav_axi_div", base + 0x80, 30);
+
+ clks[IMX8ULP_CLK_AVD_SIM] = imx_clk_hw_gate("avd_sim", "lpav_bus_div", base + 0x94, 30);
+ clks[IMX8ULP_CLK_TPM8] = imx8ulp_clk_hw_composite("tpm8", pcc5_periph_bus_sels, ARRAY_SIZE(pcc5_periph_bus_sels), true, true, true, base + 0xa0, 1);
+ clks[IMX8ULP_CLK_MU2_B] = imx_clk_hw_gate("mu2_b", "lpav_bus_div", base + 0x84, 30);
+ clks[IMX8ULP_CLK_MU3_B] = imx_clk_hw_gate("mu3_b", "lpav_bus_div", base + 0x88, 30);
+ clks[IMX8ULP_CLK_SAI6] = imx8ulp_clk_hw_composite("sai6", lpav_bus_div, 1, false, false, true, base + 0xa4, 1);
+ clks[IMX8ULP_CLK_SAI7] = imx8ulp_clk_hw_composite("sai7", lpav_bus_div, 1, false, false, true, base + 0xa8, 1);
+ clks[IMX8ULP_CLK_SPDIF] = imx8ulp_clk_hw_composite("spdif", lpav_bus_div, 1, false, false, true, base + 0xac, 1);
+ clks[IMX8ULP_CLK_ISI] = imx8ulp_clk_hw_composite("isi", lpav_axi_div, 1, false, false, true, base + 0xb0, 1);
+ clks[IMX8ULP_CLK_CSI_REGS] = imx8ulp_clk_hw_composite("csi_regs", lpav_bus_div, 1, false, false, true, base + 0xb4, 1);
+ clks[IMX8ULP_CLK_CSI] = imx8ulp_clk_hw_composite("csi", pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), true, true, true, base + 0xbc, 1);
+ clks[IMX8ULP_CLK_DSI] = imx8ulp_clk_hw_composite("dsi", pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), true, true, true, base + 0xc0, 1);
+ clks[IMX8ULP_CLK_WDOG5] = imx8ulp_clk_hw_composite("wdog5", pcc5_periph_bus_sels, ARRAY_SIZE(pcc5_periph_bus_sels), true, true, true, base + 0xc8, 1);
+ clks[IMX8ULP_CLK_EPDC] = imx8ulp_clk_hw_composite("epdc", pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), true, true, true, base + 0xcc, 1);
+ clks[IMX8ULP_CLK_PXP] = imx8ulp_clk_hw_composite("pxp", lpav_axi_div, 1, false, false, true, base + 0xd0, 1);
+ clks[IMX8ULP_CLK_GPU2D] = imx8ulp_clk_hw_composite("gpu2d", pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), true, true, true, base + 0xf0, 1);
+ clks[IMX8ULP_CLK_GPU3D] = imx8ulp_clk_hw_composite("gpu3d", pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), true, true, true, base + 0xf4, 1);
+ clks[IMX8ULP_CLK_DC_NANO] = imx8ulp_clk_hw_composite("dc_nano", pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), true, true, true, base + 0xf8, 1);
+ clks[IMX8ULP_CLK_CSI_CLK_UI] = imx8ulp_clk_hw_composite("csi_clk_ui", pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), true, true, true, base + 0x10c, 1);
+ clks[IMX8ULP_CLK_CSI_CLK_ESC] = imx8ulp_clk_hw_composite("csi_clk_esc", pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), true, true, true, base + 0x110, 1);
+ clks[IMX8ULP_CLK_RGPIOD] = imx_clk_hw_gate("rgpiod", "lpav_axi_div", base + 0x114, 30);
+ clks[IMX8ULP_CLK_DSI_TX_ESC] = imx_clk_hw_fixed_factor("mipi_dsi_tx_esc", "dsi", 1, 4);
+
+ imx_check_clk_hws(clks, clk_data->num);
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
+ if (ret)
+ return ret;
+
+ /* register the pcc5 reset controller */
+ return imx8ulp_pcc_reset_init(pdev, base, pcc5_resets, ARRAY_SIZE(pcc5_resets));
+}
+
+static int imx8ulp_clk_probe(struct platform_device *pdev)
+{
+ int (*probe)(struct platform_device *pdev);
+
+ probe = of_device_get_match_data(&pdev->dev);
+
+ if (probe)
+ return probe(pdev);
+
+ return 0;
+}
+
+static const struct of_device_id imx8ulp_clk_dt_ids[] = {
+ { .compatible = "fsl,imx8ulp-pcc3", .data = imx8ulp_clk_pcc3_init },
+ { .compatible = "fsl,imx8ulp-pcc4", .data = imx8ulp_clk_pcc4_init },
+ { .compatible = "fsl,imx8ulp-pcc5", .data = imx8ulp_clk_pcc5_init },
+ { .compatible = "fsl,imx8ulp-cgc2", .data = imx8ulp_clk_cgc2_init },
+ { .compatible = "fsl,imx8ulp-cgc1", .data = imx8ulp_clk_cgc1_init },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx8ulp_clk_dt_ids);
+
+static struct platform_driver imx8ulp_clk_driver = {
+ .probe = imx8ulp_clk_probe,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = imx8ulp_clk_dt_ids,
+ },
+};
+module_platform_driver(imx8ulp_clk_driver);
+
+MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
+MODULE_DESCRIPTION("NXP i.MX8ULP clock driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/imx/clk-lpcg-scu.c b/drivers/clk/imx/clk-lpcg-scu.c
index dd5abd09f3e2..42513c9b2e0d 100644
--- a/drivers/clk/imx/clk-lpcg-scu.c
+++ b/drivers/clk/imx/clk-lpcg-scu.c
@@ -6,6 +6,7 @@
#include <linux/bits.h>
#include <linux/clk-provider.h>
+#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/slab.h>
@@ -41,6 +42,31 @@ struct clk_lpcg_scu {
#define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw)
+/* e10858 -LPCG clock gating register synchronization errata */
+static void do_lpcg_workaround(u32 rate, void __iomem *reg, u32 val)
+{
+ writel(val, reg);
+
+ if (rate >= 24000000 || rate == 0) {
+ u32 reg1;
+
+ /*
+ * The time taken to access the LPCG registers from the AP core
+ * through the interconnect is longer than the minimum delay
+ * of 4 clock cycles required by the errata.
+ * Adding a readl will provide sufficient delay to prevent
+ * back-to-back writes.
+ */
+ reg1 = readl(reg);
+ } else {
+ /*
+ * For clocks running below 24MHz, wait a minimum of
+ * 4 clock cycles.
+ */
+ ndelay(4 * (DIV_ROUND_UP(1000000000, rate)));
+ }
+}
+
static int clk_lpcg_scu_enable(struct clk_hw *hw)
{
struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
@@ -57,7 +83,8 @@ static int clk_lpcg_scu_enable(struct clk_hw *hw)
val |= CLK_GATE_SCU_LPCG_HW_SEL;
reg |= val << clk->bit_idx;
- writel(reg, clk->reg);
+
+ do_lpcg_workaround(clk_hw_get_rate(hw), clk->reg, reg);
spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
@@ -74,7 +101,7 @@ static void clk_lpcg_scu_disable(struct clk_hw *hw)
reg = readl_relaxed(clk->reg);
reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);
- writel(reg, clk->reg);
+ do_lpcg_workaround(clk_hw_get_rate(hw), clk->reg, reg);
spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
}
@@ -135,6 +162,9 @@ static int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev)
{
struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
+ if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg")))
+ return 0;
+
clk->state = readl_relaxed(clk->reg);
dev_dbg(dev, "save lpcg state 0x%x\n", clk->state);
@@ -145,13 +175,16 @@ static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev)
{
struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
+ if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg")))
+ return 0;
+
/*
* FIXME: Sometimes writes don't work unless the CPU issues
* them twice
*/
writel(clk->state, clk->reg);
- writel(clk->state, clk->reg);
+ do_lpcg_workaround(0, clk->reg, clk->state);
dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state);
return 0;
diff --git a/drivers/clk/imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c
index 5d2a9a3be95e..6c39b8c5ae4d 100644
--- a/drivers/clk/imx/clk-pfd.c
+++ b/drivers/clk/imx/clk-pfd.c
@@ -5,9 +5,11 @@
*/
#include <linux/clk-provider.h>
+#include <linux/imx_sema4.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <soc/imx/src.h>
#include "clk.h"
/**
@@ -32,20 +34,57 @@ struct clk_pfd {
#define CLR 0x8
#define OTG 0xc
-static int clk_pfd_enable(struct clk_hw *hw)
+static void clk_pfd_do_hardware(struct clk_pfd *pfd, bool enable)
+{
+ if (enable)
+ writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR);
+ else
+ writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET);
+}
+
+static void clk_pfd_do_shared_clks(struct clk_hw *hw, bool enable)
{
struct clk_pfd *pfd = to_clk_pfd(hw);
- writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR);
+ if (imx_src_is_m4_enabled() && clk_on_imx6sx()) {
+#ifdef CONFIG_SOC_IMX6SX
+ if (!amp_power_mutex || !shared_mem) {
+ if (enable)
+ clk_pfd_do_hardware(pfd, enable);
+ return;
+ }
+
+ imx_sema4_mutex_lock(amp_power_mutex);
+ if (shared_mem->ca9_valid != SHARED_MEM_MAGIC_NUMBER ||
+ shared_mem->cm4_valid != SHARED_MEM_MAGIC_NUMBER) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+
+ if (!imx_update_shared_mem(hw, enable)) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+
+ clk_pfd_do_hardware(pfd, enable);
+
+ imx_sema4_mutex_unlock(amp_power_mutex);
+#endif
+ } else {
+ clk_pfd_do_hardware(pfd, enable);
+ }
+}
+
+static int clk_pfd_enable(struct clk_hw *hw)
+{
+ clk_pfd_do_shared_clks(hw, true);
return 0;
}
static void clk_pfd_disable(struct clk_hw *hw)
{
- struct clk_pfd *pfd = to_clk_pfd(hw);
-
- writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET);
+ clk_pfd_do_shared_clks(hw, false);
}
static unsigned long clk_pfd_recalc_rate(struct clk_hw *hw,
diff --git a/drivers/clk/imx/clk-pfdv2.c b/drivers/clk/imx/clk-pfdv2.c
index 6b744c84278e..6ca53a960eb7 100644
--- a/drivers/clk/imx/clk-pfdv2.c
+++ b/drivers/clk/imx/clk-pfdv2.c
@@ -161,8 +161,17 @@ static int clk_pfdv2_set_rate(struct clk_hw *hw, unsigned long rate,
if (!rate)
return -EINVAL;
- /* PFD can NOT change rate without gating */
- WARN_ON(clk_pfdv2_is_enabled(hw));
+ /*
+ * PFD can NOT change rate without gating.
+ * as the PFDs may enabled in HW by default but no
+ * consumer used it, the enable count is '0', so the
+ * 'SET_RATE_GATE' can NOT help on blocking the set_rate
+ * ops especially for 'assigned-clock-xxx'. In order
+ * to simplify the case, just disable the PFD if it is
+ * enabled in HW but not in SW.
+ */
+ if (clk_pfdv2_is_enabled(hw))
+ clk_pfdv2_disable(hw);
tmp = tmp * 18 + rate / 2;
do_div(tmp, rate);
@@ -191,8 +200,8 @@ static const struct clk_ops clk_pfdv2_ops = {
.is_enabled = clk_pfdv2_is_enabled,
};
-struct clk_hw *imx_clk_hw_pfdv2(const char *name, const char *parent_name,
- void __iomem *reg, u8 idx)
+struct clk_hw *imx_clk_hw_pfdv2(enum imx_pfdv2_type type, const char *name,
+ const char *parent_name, void __iomem *reg, u8 idx)
{
struct clk_init_data init;
struct clk_pfdv2 *pfd;
@@ -214,7 +223,10 @@ struct clk_hw *imx_clk_hw_pfdv2(const char *name, const char *parent_name,
init.ops = &clk_pfdv2_ops;
init.parent_names = &parent_name;
init.num_parents = 1;
- init.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT;
+ if (type == IMX_PFDV2_IMX7ULP)
+ init.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT;
+ else
+ init.flags = CLK_SET_RATE_GATE;
pfd->hw.init = &init;
@@ -227,3 +239,4 @@ struct clk_hw *imx_clk_hw_pfdv2(const char *name, const char *parent_name,
return hw;
}
+EXPORT_SYMBOL_GPL(imx_clk_hw_pfdv2);
diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c
index 2b5ed86b9dbb..1563a7bff422 100644
--- a/drivers/clk/imx/clk-pll14xx.c
+++ b/drivers/clk/imx/clk-pll14xx.c
@@ -137,9 +137,12 @@ static unsigned long clk_pll1443x_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
+ const struct imx_pll14xx_rate_table *rate_table = pll->rate_table;
u32 mdiv, pdiv, sdiv, pll_div_ctl0, pll_div_ctl1;
short int kdiv;
u64 fvco = parent_rate;
+ long rate = 0;
+ int i;
pll_div_ctl0 = readl_relaxed(pll->base + 4);
pll_div_ctl1 = readl_relaxed(pll->base + 8);
@@ -148,13 +151,25 @@ static unsigned long clk_pll1443x_recalc_rate(struct clk_hw *hw,
sdiv = (pll_div_ctl0 & SDIV_MASK) >> SDIV_SHIFT;
kdiv = pll_div_ctl1 & KDIV_MASK;
+ /*
+ * Sometimes, the recalculated rate has deviation due to
+ * the frac part. So find the accurate pll rate from the table
+ * first, if no match rate in the table, use the rate calculated
+ * from the equation below.
+ */
+ for (i = 0; i < pll->rate_count; i++) {
+ if (rate_table[i].pdiv == pdiv && rate_table[i].mdiv == mdiv &&
+ rate_table[i].sdiv == sdiv && rate_table[i].kdiv == kdiv)
+ rate = rate_table[i].rate;
+ }
+
/* fvco = (m * 65536 + k) * Fin / (p * 65536) */
fvco *= (mdiv * 65536 + kdiv);
pdiv *= 65536;
do_div(fvco, pdiv << sdiv);
- return fvco;
+ return rate ? (unsigned long) rate : (unsigned long)fvco;
}
static inline bool clk_pll14xx_mp_change(const struct imx_pll14xx_rate_table *rate,
@@ -360,6 +375,26 @@ static void clk_pll14xx_unprepare(struct clk_hw *hw)
writel_relaxed(val, pll->base + GNRL_CTL);
}
+void clk_set_delta_k(struct clk_hw *hw, short int delta_k)
+{
+ struct clk_pll14xx *pll = to_clk_pll14xx(hw);
+ short int k;
+ u32 val;
+
+ val = readl_relaxed(pll->base + 8);
+ k = (val & KDIV_MASK) + delta_k;
+ writel_relaxed(k << KDIV_SHIFT, pll->base + 8);
+}
+
+void clk_get_pll_setting(struct clk_hw *hw, u32 *pll_div_ctrl0,
+ u32 *pll_div_ctrl1)
+{
+ struct clk_pll14xx *pll = to_clk_pll14xx(hw);
+
+ *pll_div_ctrl0 = readl_relaxed(pll->base + 4);
+ *pll_div_ctrl1 = readl_relaxed(pll->base + 8);
+}
+
static const struct clk_ops clk_pll1416x_ops = {
.prepare = clk_pll14xx_prepare,
.unprepare = clk_pll14xx_unprepare,
diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c
index 20ee9611ba6e..5fd4765e633b 100644
--- a/drivers/clk/imx/clk-pllv3.c
+++ b/drivers/clk/imx/clk-pllv3.c
@@ -8,9 +8,11 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/iopoll.h>
+#include <linux/imx_sema4.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/err.h>
+#include <soc/imx/src.h>
#include "clk.h"
#define PLL_NUM_OFFSET 0x10
@@ -65,36 +67,82 @@ static int clk_pllv3_wait_lock(struct clk_pllv3 *pll)
if ((pll->powerup_set && !val) || (!pll->powerup_set && val))
return 0;
- return readl_relaxed_poll_timeout(pll->base, val, val & BM_PLL_LOCK,
- 500, PLL_LOCK_TIMEOUT);
+ if (!(imx_src_is_m4_enabled() && clk_on_imx6sx()))
+ return readl_relaxed_poll_timeout(pll->base, val, val & BM_PLL_LOCK,
+ 500, PLL_LOCK_TIMEOUT);
+ else
+ return readl_relaxed_poll_timeout_atomic(pll->base, val, val & BM_PLL_LOCK,
+ 10, PLL_LOCK_TIMEOUT);
}
-static int clk_pllv3_prepare(struct clk_hw *hw)
+static int clk_pllv3_do_hardware(struct clk_hw *hw, bool enable)
{
struct clk_pllv3 *pll = to_clk_pllv3(hw);
+ int ret;
u32 val;
val = readl_relaxed(pll->base);
- if (pll->powerup_set)
- val |= pll->power_bit;
- else
- val &= ~pll->power_bit;
- writel_relaxed(val, pll->base);
+ if (enable) {
+ if (pll->powerup_set)
+ val |= pll->power_bit;
+ else
+ val &= ~pll->power_bit;
+ writel_relaxed(val, pll->base);
+
+ ret = clk_pllv3_wait_lock(pll);
+ if (ret)
+ return ret;
+ } else {
+ if (pll->powerup_set)
+ val &= ~pll->power_bit;
+ else
+ val |= pll->power_bit;
+ writel_relaxed(val, pll->base);
+ }
- return clk_pllv3_wait_lock(pll);
+ return 0;
}
-static void clk_pllv3_unprepare(struct clk_hw *hw)
+static void clk_pllv3_do_shared_clks(struct clk_hw *hw, bool enable)
{
- struct clk_pllv3 *pll = to_clk_pllv3(hw);
- u32 val;
+ if (imx_src_is_m4_enabled() && clk_on_imx6sx()) {
+#ifdef CONFIG_SOC_IMX6SX
+ if (!amp_power_mutex || !shared_mem) {
+ if (enable)
+ clk_pllv3_do_hardware(hw, enable);
+ return;
+ }
+
+ imx_sema4_mutex_lock(amp_power_mutex);
+ if (shared_mem->ca9_valid != SHARED_MEM_MAGIC_NUMBER ||
+ shared_mem->cm4_valid != SHARED_MEM_MAGIC_NUMBER) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+
+ if (!imx_update_shared_mem(hw, enable)) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+ clk_pllv3_do_hardware(hw, enable);
+
+ imx_sema4_mutex_unlock(amp_power_mutex);
+#endif
+ } else {
+ clk_pllv3_do_hardware(hw, enable);
+ }
+}
- val = readl_relaxed(pll->base);
- if (pll->powerup_set)
- val &= ~pll->power_bit;
- else
- val |= pll->power_bit;
- writel_relaxed(val, pll->base);
+static int clk_pllv3_prepare(struct clk_hw *hw)
+{
+ clk_pllv3_do_shared_clks(hw, true);
+
+ return 0;
+}
+
+static void clk_pllv3_unprepare(struct clk_hw *hw)
+{
+ clk_pllv3_do_shared_clks(hw, false);
}
static int clk_pllv3_is_prepared(struct clk_hw *hw)
diff --git a/drivers/clk/imx/clk-pllv4.c b/drivers/clk/imx/clk-pllv4.c
index 8ec703f27417..6e7e34571fc8 100644
--- a/drivers/clk/imx/clk-pllv4.c
+++ b/drivers/clk/imx/clk-pllv4.c
@@ -23,14 +23,17 @@
/* PLL Configuration Register (xPLLCFG) */
#define PLL_CFG_OFFSET 0x08
+#define IMX8ULP_PLL_CFG_OFFSET 0x10
#define BP_PLL_MULT 16
#define BM_PLL_MULT (0x7f << 16)
/* PLL Numerator Register (xPLLNUM) */
#define PLL_NUM_OFFSET 0x10
+#define IMX8ULP_PLL_NUM_OFFSET 0x1c
/* PLL Denominator Register (xPLLDENOM) */
#define PLL_DENOM_OFFSET 0x14
+#define IMX8ULP_PLL_DENOM_OFFSET 0x18
#define MAX_MFD 0x3fffffff
#define DEFAULT_MFD 1000000
@@ -38,6 +41,9 @@
struct clk_pllv4 {
struct clk_hw hw;
void __iomem *base;
+ u32 cfg_offset;
+ u32 num_offset;
+ u32 denom_offset;
};
/* Valid PLL MULT Table */
@@ -72,12 +78,12 @@ static unsigned long clk_pllv4_recalc_rate(struct clk_hw *hw,
u32 mult, mfn, mfd;
u64 temp64;
- mult = readl_relaxed(pll->base + PLL_CFG_OFFSET);
+ mult = readl_relaxed(pll->base + pll->cfg_offset);
mult &= BM_PLL_MULT;
mult >>= BP_PLL_MULT;
- mfn = readl_relaxed(pll->base + PLL_NUM_OFFSET);
- mfd = readl_relaxed(pll->base + PLL_DENOM_OFFSET);
+ mfn = readl_relaxed(pll->base + pll->num_offset);
+ mfd = readl_relaxed(pll->base + pll->denom_offset);
temp64 = parent_rate;
temp64 *= mfn;
do_div(temp64, mfd);
@@ -165,13 +171,13 @@ static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate,
do_div(temp64, parent_rate);
mfn = temp64;
- val = readl_relaxed(pll->base + PLL_CFG_OFFSET);
+ val = readl_relaxed(pll->base + pll->cfg_offset);
val &= ~BM_PLL_MULT;
val |= mult << BP_PLL_MULT;
- writel_relaxed(val, pll->base + PLL_CFG_OFFSET);
+ writel_relaxed(val, pll->base + pll->cfg_offset);
- writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET);
- writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET);
+ writel_relaxed(mfn, pll->base + pll->num_offset);
+ writel_relaxed(mfd, pll->base + pll->denom_offset);
return 0;
}
@@ -207,8 +213,8 @@ static const struct clk_ops clk_pllv4_ops = {
.is_prepared = clk_pllv4_is_prepared,
};
-struct clk_hw *imx_clk_hw_pllv4(const char *name, const char *parent_name,
- void __iomem *base)
+struct clk_hw *imx_clk_hw_pllv4(enum imx_pllv4_type type, const char *name,
+ const char *parent_name, void __iomem *base)
{
struct clk_pllv4 *pll;
struct clk_hw *hw;
@@ -221,6 +227,16 @@ struct clk_hw *imx_clk_hw_pllv4(const char *name, const char *parent_name,
pll->base = base;
+ if (type == IMX_PLLV4_IMX8ULP) {
+ pll->cfg_offset = IMX8ULP_PLL_CFG_OFFSET;
+ pll->num_offset = IMX8ULP_PLL_NUM_OFFSET;
+ pll->denom_offset = IMX8ULP_PLL_DENOM_OFFSET;
+ } else {
+ pll->cfg_offset = PLL_CFG_OFFSET;
+ pll->num_offset = PLL_NUM_OFFSET;
+ pll->denom_offset = PLL_DENOM_OFFSET;
+ }
+
init.name = name;
init.ops = &clk_pllv4_ops;
init.parent_names = &parent_name;
@@ -238,3 +254,4 @@ struct clk_hw *imx_clk_hw_pllv4(const char *name, const char *parent_name,
return hw;
}
+EXPORT_SYMBOL_GPL(imx_clk_hw_pllv4);
diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c
index 083da31dc3ea..97eb44ea2767 100644
--- a/drivers/clk/imx/clk-scu.c
+++ b/drivers/clk/imx/clk-scu.c
@@ -9,11 +9,13 @@
#include <linux/bsearch.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
+#include <linux/firmware/imx/svc/rm.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
+#include <xen/xen.h>
#include "clk-scu.h"
@@ -481,7 +483,7 @@ struct clk_hw *__imx_clk_scu(struct device *dev, const char *name,
* clock status from HW instead of using the possible invalid
* cached rate.
*/
- init.flags = CLK_GET_RATE_NOCACHE;
+ init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_PARENT_NOCACHE;
clk->hw.init = &init;
hw = &clk->hw;
@@ -577,6 +579,7 @@ static int __maybe_unused imx_clk_scu_suspend(struct device *dev)
clk->rate = clk_scu_recalc_rate(&clk->hw, 0);
else
clk->rate = clk_hw_get_rate(&clk->hw);
+
clk->is_enabled = clk_hw_is_enabled(&clk->hw);
if (clk->parent)
@@ -650,9 +653,34 @@ static int imx_clk_scu_attach_pd(struct device *dev, u32 rsrc_id)
rsrc_id == IMX_SC_R_A72)
return 0;
+ /*
+ * Temp fix to avoid the uart clk attached pd power off uart_0
+ */
+ if (rsrc_id == IMX_SC_R_UART_0 && xen_initial_domain())
+ return 0;
+
return of_genpd_add_device(&genpdspec, dev);
}
+static bool imx_clk_is_resource_owned(u32 rsrc)
+{
+ /*
+ * A-core resources are special. SCFW reports they are not "owned" by
+ * current partition but linux can still adjust them for cpufreq.
+ *
+ * So force this to return false when running as a VM guest and always
+ * true otherwise.
+ */
+ if (rsrc == IMX_SC_R_A53 || rsrc == IMX_SC_R_A72 ||
+ rsrc == IMX_SC_R_A35) {
+ if (xen_domain() && !xen_initial_domain())
+ return false;
+ return true;
+ }
+
+ return imx_sc_rm_is_resource_owned(ccm_ipc_handle, rsrc);
+}
+
struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
const char * const *parents,
int num_parents, u32 rsrc_id, u8 clk_type)
@@ -670,6 +698,9 @@ struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
if (!imx_scu_clk_is_valid(rsrc_id))
return ERR_PTR(-EINVAL);
+ if (!imx_clk_is_resource_owned(rsrc_id))
+ return NULL;
+
pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE);
if (!pdev) {
pr_err("%s: failed to allocate scu clk dev rsrc %d type %d\n",
@@ -833,13 +864,13 @@ struct clk_hw *__imx_clk_gpr_scu(const char *name, const char * const *parent_na
if (rsrc_id >= IMX_SC_R_LAST || gpr_id >= IMX_SC_C_LAST)
return ERR_PTR(-EINVAL);
+ if (!imx_scu_clk_is_valid(rsrc_id))
+ return ERR_PTR(-EINVAL);
+
clk_node = kzalloc(sizeof(*clk_node), GFP_KERNEL);
if (!clk_node)
return ERR_PTR(-ENOMEM);
- if (!imx_scu_clk_is_valid(rsrc_id))
- return ERR_PTR(-EINVAL);
-
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
if (!clk) {
kfree(clk_node);
diff --git a/drivers/clk/imx/clk-scu.h b/drivers/clk/imx/clk-scu.h
index 22156e93b85d..7d8069886b0c 100644
--- a/drivers/clk/imx/clk-scu.h
+++ b/drivers/clk/imx/clk-scu.h
@@ -23,6 +23,7 @@ extern struct list_head imx_scu_clks[];
extern const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops;
extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qxp;
extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qm;
+extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8dxl;
int imx_clk_scu_init(struct device_node *np,
const struct imx_clk_scu_rsrc_table *data);
diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c
index 7cc669934253..c7e6020f6382 100644
--- a/drivers/clk/imx/clk.c
+++ b/drivers/clk/imx/clk.c
@@ -17,6 +17,8 @@
DEFINE_SPINLOCK(imx_ccm_lock);
EXPORT_SYMBOL_GPL(imx_ccm_lock);
+bool uart_from_osc;
+
void imx_unregister_clocks(struct clk *clks[], unsigned int count)
{
unsigned int i;
@@ -194,6 +196,9 @@ void imx_register_uart_clocks(unsigned int clk_count)
static int __init imx_clk_disable_uart(void)
{
+ if (imx_src_is_m4_enabled())
+ return 0;
+
if (imx_keep_uart_clocks && imx_enabled_uart_clocks) {
int i;
@@ -207,6 +212,14 @@ static int __init imx_clk_disable_uart(void)
return 0;
}
late_initcall_sync(imx_clk_disable_uart);
+
+static int __init setup_uart_clk(char *uart_rate)
+{
+ uart_from_osc = true;
+ return 1;
+}
+__setup("uart_from_osc", setup_uart_clk);
+
#endif
MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index e144f983fd8c..85a641ec2023 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -5,6 +5,7 @@
#include <linux/bits.h>
#include <linux/spinlock.h>
#include <linux/clk-provider.h>
+#include <soc/imx/src.h>
extern spinlock_t imx_ccm_lock;
@@ -22,6 +23,9 @@ void imx_unregister_clocks(struct clk *clks[], unsigned int count);
void imx_unregister_hw_clocks(struct clk_hw *hws[], unsigned int count);
extern void imx_cscmr1_fixup(u32 *val);
+extern struct imx_sema4_mutex *amp_power_mutex;
+extern struct imx_shared_mem *shared_mem;
+extern bool uart_from_osc;
enum imx_pllv1_type {
IMX_PLLV1_IMX1,
@@ -42,6 +46,16 @@ enum imx_pll14xx_type {
PLL_1443X,
};
+enum imx_pllv4_type {
+ IMX_PLLV4_IMX7ULP,
+ IMX_PLLV4_IMX8ULP,
+};
+
+enum imx_pfdv2_type {
+ IMX_PFDV2_IMX7ULP,
+ IMX_PFDV2_IMX8ULP,
+};
+
/* NOTE: Rate table should be kept sorted in descending order. */
struct imx_pll14xx_rate_table {
unsigned int rate;
@@ -171,6 +185,25 @@ enum imx_pllv3_type {
IMX_PLLV3_AV_IMX7,
};
+#define MAX_SHARED_CLK_NUMBER 100
+#define SHARED_MEM_MAGIC_NUMBER 0x12345678
+#define MCC_POWER_SHMEM_NUMBER (6)
+
+struct imx_shared_clk {
+ struct clk *self;
+ struct clk *parent;
+ void *m4_clk;
+ void *m4_clk_parent;
+ u8 ca9_enabled;
+ u8 cm4_enabled;
+};
+
+struct imx_shared_mem {
+ u32 ca9_valid;
+ u32 cm4_valid;
+ struct imx_shared_clk imx_clk[MAX_SHARED_CLK_NUMBER];
+};
+
struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name,
const char *parent_name, void __iomem *base, u32 div_mask);
@@ -191,8 +224,8 @@ struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name,
.kdiv = (_k), \
}
-struct clk_hw *imx_clk_hw_pllv4(const char *name, const char *parent_name,
- void __iomem *base);
+struct clk_hw *imx_clk_hw_pllv4(enum imx_pllv4_type type, const char *name,
+ const char *parent_name, void __iomem *base);
struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
@@ -215,8 +248,8 @@ struct clk_hw *imx_clk_hw_gate_exclusive(const char *name, const char *parent,
struct clk_hw *imx_clk_hw_pfd(const char *name, const char *parent_name,
void __iomem *reg, u8 idx);
-struct clk_hw *imx_clk_hw_pfdv2(const char *name, const char *parent_name,
- void __iomem *reg, u8 idx);
+struct clk_hw *imx_clk_hw_pfdv2(enum imx_pfdv2_type type, const char *name,
+ const char *parent_name, void __iomem *reg, u8 idx);
struct clk_hw *imx_clk_hw_busy_divider(const char *name, const char *parent_name,
void __iomem *reg, u8 shift, u8 width,
@@ -226,12 +259,25 @@ struct clk_hw *imx_clk_hw_busy_mux(const char *name, void __iomem *reg, u8 shift
u8 width, void __iomem *busy_reg, u8 busy_shift,
const char * const *parent_names, int num_parents);
+int imx_update_shared_mem(struct clk_hw *hw, bool enable);
+
+static inline int clk_on_imx6sx(void)
+{
+ return of_machine_is_compatible("fsl,imx6sx");
+}
+
struct clk_hw *imx7ulp_clk_hw_composite(const char *name,
const char * const *parent_names,
int num_parents, bool mux_present,
bool rate_present, bool gate_present,
void __iomem *reg);
+struct clk_hw *imx8ulp_clk_hw_composite(const char *name,
+ const char * const *parent_names,
+ int num_parents, bool mux_present,
+ bool rate_present, bool gate_present,
+ void __iomem *reg, bool has_swrst);
+
struct clk_hw *imx_clk_hw_fixup_divider(const char *name, const char *parent,
void __iomem *reg, u8 shift, u8 width,
void (*fixup)(u32 *val));
@@ -284,6 +330,15 @@ static inline struct clk_hw *imx_clk_hw_divider(const char *name,
reg, shift, width, 0, &imx_ccm_lock);
}
+static inline struct clk_hw *imx_clk_hw_divider_closest(const char *name,
+ const char *parent,
+ void __iomem *reg, u8 shift,
+ u8 width)
+{
+ return clk_hw_register_divider(NULL, name, parent, 0,
+ reg, shift, width, CLK_DIVIDER_ROUND_CLOSEST, &imx_ccm_lock);
+}
+
static inline struct clk_hw *imx_clk_hw_divider_flags(const char *name,
const char *parent,
void __iomem *reg, u8 shift,
@@ -381,7 +436,7 @@ static inline struct clk_hw *imx_dev_clk_hw_gate_shared(struct device *dev,
void __iomem *reg, u8 shift,
unsigned int *share_count)
{
- return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
+ return clk_hw_register_gate2(dev, name, parent, CLK_SET_RATE_PARENT |
CLK_OPS_PARENT_ENABLE, reg, shift, 0x1,
0x1, 0, &imx_ccm_lock, share_count);
}
@@ -396,7 +451,17 @@ static inline struct clk *imx_clk_gate2_cgr(const char *name,
static inline struct clk_hw *imx_clk_hw_gate3(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
- return clk_hw_register_gate(NULL, name, parent,
+ /*
+ * per design team's suggestion, clk root is NOT consuming
+ * much power, and clk root enable/disable does NOT have domain
+ * control, so they suggest to leave clk root always on when
+ * M4 is enabled.
+ */
+ if (imx_src_is_m4_enabled())
+ return clk_hw_register_fixed_factor(NULL, name, parent,
+ CLK_SET_RATE_PARENT, 1, 1);
+ else
+ return clk_hw_register_gate(NULL, name, parent,
CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, 0, &imx_ccm_lock);
}
@@ -451,6 +516,15 @@ static inline struct clk_hw *imx_dev_clk_hw_mux(struct device *dev,
reg, shift, width, 0, &imx_ccm_lock);
}
+static inline struct clk *imx_dev_clk_mux(struct device *dev, const char *name,
+ void __iomem *reg, u8 shift, u8 width,
+ const char * const *parents, int num_parents)
+{
+ return clk_register_mux(dev, name, parents, num_parents,
+ CLK_SET_RATE_NO_REPARENT | CLK_SET_PARENT_GATE,
+ reg, shift, width, 0, &imx_ccm_lock);
+}
+
static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg,
u8 shift, u8 width, const char * const *parents,
int num_parents)
@@ -598,4 +672,7 @@ struct clk_hw *imx_clk_hw_divider_gate(const char *name, const char *parent_name
unsigned long flags, void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock);
+
+void clk_set_delta_k(struct clk_hw *hw, short int delta_k);
+void clk_get_pll_setting(struct clk_hw *hw, u32 *pll_div_ctrl0, u32 *pll_div_ctrl1);
#endif
diff --git a/drivers/clk/s32/Kconfig b/drivers/clk/s32/Kconfig
new file mode 100644
index 000000000000..c28bdbbfaa3a
--- /dev/null
+++ b/drivers/clk/s32/Kconfig
@@ -0,0 +1,4 @@
+config ARCH_S32_CLK
+ bool "Enable S32 CLK Framework"
+ help
+ Support for the Clock Framework on S32 SoCs.
diff --git a/drivers/clk/s32/Makefile b/drivers/clk/s32/Makefile
new file mode 100644
index 000000000000..169b8b5900f9
--- /dev/null
+++ b/drivers/clk/s32/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ARCH_S32_CLK) += clk-core.o
+obj-$(CONFIG_ARCH_S32_CLK) += s32v234/
diff --git a/drivers/clk/s32/clk-core.c b/drivers/clk/s32/clk-core.c
new file mode 100644
index 000000000000..a8cca66f7959
--- /dev/null
+++ b/drivers/clk/s32/clk-core.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include "clk.h"
+
+void __init s32_check_clocks(struct clk *clks[], unsigned int count)
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++)
+ if (IS_ERR(clks[i]))
+ pr_err("S32 clk %u: register failed with %ld\n",
+ i, PTR_ERR(clks[i]));
+}
+
+static struct clk * __init s32_obtain_fixed_clock_from_dt(const char *name)
+{
+ struct of_phandle_args phandle;
+ struct clk *clk = ERR_PTR(-ENODEV);
+ char *path;
+
+ path = kasprintf(GFP_KERNEL, "/clocks/%s", name);
+ if (!path)
+ return ERR_PTR(-ENOMEM);
+
+ phandle.np = of_find_node_by_path(path);
+ kfree(path);
+
+ if (phandle.np) {
+ clk = of_clk_get_from_provider(&phandle);
+ of_node_put(phandle.np);
+ }
+ return clk;
+}
+
+struct clk * __init s32_obtain_fixed_clock(
+ const char *name, unsigned long rate)
+{
+ struct clk *clk;
+
+ clk = s32_obtain_fixed_clock_from_dt(name);
+ if (IS_ERR(clk))
+ clk = s32_clk_fixed(name, rate);
+ return clk;
+}
diff --git a/drivers/clk/s32/clk.h b/drivers/clk/s32/clk.h
new file mode 100644
index 000000000000..83100641158f
--- /dev/null
+++ b/drivers/clk/s32/clk.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ */
+
+#ifndef __MACH_S32_CLK_H
+#define __MACH_S32_CLK_H
+
+#include <linux/spinlock.h>
+#include <linux/clk-provider.h>
+
+#define PNAME(x) \
+ static const char *x[] __initconst
+
+void s32_check_clocks(struct clk *clks[], unsigned int count);
+
+struct clk *s32_obtain_fixed_clock(
+ const char *name, unsigned long rate);
+
+static inline struct clk *s32_clk_fixed(const char *name, unsigned long rate)
+{
+ return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
+}
+
+static inline struct clk *s32_clk_divider(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, u8 width,
+ spinlock_t *lock)
+{
+ struct clk *tmp_clk = clk_register_divider(NULL, name, parent,
+ CLK_SET_RATE_PARENT,
+ reg, shift, width, 0, lock);
+
+ return tmp_clk;
+}
+
+static inline struct clk *s32_clk_mux(const char *name, void __iomem *reg,
+ u8 shift, u8 width, const char **parents,
+ u8 num_parents, spinlock_t *lock)
+{
+ return clk_register_mux(NULL, name, parents, num_parents,
+ CLK_SET_RATE_NO_REPARENT, reg, shift,
+ width, 0, lock);
+}
+
+static inline struct clk *s32_clk_fixed_factor(const char *name,
+ const char *parent,
+ unsigned int mult,
+ unsigned int div)
+{
+ return clk_register_fixed_factor(NULL, name, parent,
+ CLK_SET_RATE_PARENT, mult, div);
+}
+
+#endif
diff --git a/drivers/clk/s32/s32v234/Makefile b/drivers/clk/s32/s32v234/Makefile
new file mode 100644
index 000000000000..7ddf9f4b5d81
--- /dev/null
+++ b/drivers/clk/s32/s32v234/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ARCH_S32_CLK) += clk.o clk-plldig.o clk-dfs.o
diff --git a/drivers/clk/s32/s32v234/clk-dfs.c b/drivers/clk/s32/s32v234/clk-dfs.c
new file mode 100644
index 000000000000..2bd569e13a18
--- /dev/null
+++ b/drivers/clk/s32/s32v234/clk-dfs.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include "clk.h"
+
+/**
+ * struct clk_dfs - S32 DFS clock
+ * @clk_hw: clock source
+ * @reg: DFS register address
+ * @idx: the index of DFS encoded in the register
+ *
+ * DFS clock found on S32 series. Each register for DFS has 4 clk_dfs
+ * data encoded, and member idx is used to specify the one.
+ * Only ARMPLL(3 DFS), ENETPLL(4 DFS) and DDRPLL(3 DFS) has DFS outputs.
+ */
+struct clk_dfs {
+ struct clk_hw hw;
+ void __iomem *reg;
+ enum s32v234_plldig_type plltype;
+ u8 idx;
+ u32 mfn;
+};
+
+#define to_clk_dfs(_hw) container_of(_hw, struct clk_dfs, hw)
+
+static int get_pllx_dfs_nr(enum s32v234_plldig_type plltype)
+{
+ switch (plltype) {
+ case S32_PLLDIG_ARM:
+ return ARMPLL_DFS_NR;
+ case S32_PLLDIG_ENET:
+ return ENETPLL_DFS_NR;
+ case S32_PLLDIG_DDR:
+ return DDRPLL_DFS_NR;
+ case S32_PLLDIG_PERIPH:
+ case S32_PLLDIG_VIDEO:
+ pr_warn("Current selected PLL has no DFS\n");
+ break;
+ }
+
+ return -EINVAL;
+}
+static unsigned long get_pllx_dfsy_max_rate(enum s32v234_plldig_type plltype,
+ int dfsno)
+{
+ switch (plltype) {
+ case S32_PLLDIG_ARM:
+ switch (dfsno) {
+ case 0:
+ return ARMPLL_DFS0_MAX_RATE;
+ case 1:
+ return ARMPLL_DFS1_MAX_RATE;
+ case 2:
+ return ARMPLL_DFS2_MAX_RATE;
+ }
+ break;
+ case S32_PLLDIG_ENET:
+ switch (dfsno) {
+ case 0:
+ return ENETPLL_DFS0_MAX_RATE;
+ case 1:
+ return ENETPLL_DFS1_MAX_RATE;
+ case 2:
+ return ENETPLL_DFS2_MAX_RATE;
+ case 3:
+ return ENETPLL_DFS3_MAX_RATE;
+ }
+ break;
+ case S32_PLLDIG_DDR:
+ switch (dfsno) {
+ case 0:
+ return DDRPLL_DFS0_MAX_RATE;
+ case 1:
+ return DDRPLL_DFS1_MAX_RATE;
+ case 2:
+ return DDRPLL_DFS2_MAX_RATE;
+ }
+ break;
+ case S32_PLLDIG_PERIPH:
+ case S32_PLLDIG_VIDEO:
+ pr_warn("Current selected PLL has no DFS.");
+ break;
+ default:
+ pr_warn("Unsupported PLL. Use %d or %d\n",
+ S32_PLLDIG_ARM, S32_PLLDIG_VIDEO);
+ break;
+ }
+
+ return -EINVAL;
+}
+static int clk_dfs_enable(struct clk_hw *hw)
+{
+ /*
+ * TODO: When SOC is available, this function
+ * should be tested and implemented for DFS
+ * if it is possible
+ */
+ return 0;
+}
+
+static void clk_dfs_disable(struct clk_hw *hw)
+{
+ /*
+ * TODO: When SOC is available, this function
+ * should be tested and implemented for DFS
+ * if it is possible
+ */
+}
+
+static unsigned long clk_dfs_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_dfs *dfs = to_clk_dfs(hw);
+ u32 mfn, mfi, rate;
+ u32 dvport = readl_relaxed(DFS_DVPORTn(dfs->reg, dfs->idx));
+
+ mfn = (dvport & DFS_DVPORTn_MFN_MASK) >> DFS_DVPORTn_MFN_OFFSET;
+ mfi = (dvport & DFS_DVPORTn_MFI_MASK) >> DFS_DVPORTn_MFI_OFFSET;
+ mfi <<= 8;
+ rate = parent_rate / (mfi + mfn);
+ rate <<= 8;
+
+ return rate;
+}
+
+static long clk_dfs_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_dfs *dfs = to_clk_dfs(hw);
+ unsigned long max_allowed_rate;
+
+ max_allowed_rate = get_pllx_dfsy_max_rate(dfs->plltype, dfs->idx);
+
+ if (rate > max_allowed_rate)
+ rate = max_allowed_rate;
+
+ return rate;
+}
+
+static int clk_dfs_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_dfs *dfs = to_clk_dfs(hw);
+ u32 mfi;
+ u32 portreset = readl_relaxed(DFS_PORTRESET(dfs->reg));
+
+ writel_relaxed(DFS_CTRL_DLL_RESET, DFS_CTRL(dfs->reg));
+ writel_relaxed(portreset | ~DFS_PORTRESET_PORTRESET_SET(dfs->idx),
+ DFS_PORTRESET(dfs->reg));
+
+ mfi = parent_rate/rate;
+ writel_relaxed(DFS_DVPORTn_MFI_SET(mfi) |
+ DFS_DVPORTn_MFN_SET(dfs->mfn),
+ DFS_DVPORTn(dfs->reg, dfs->idx));
+
+ writel_relaxed(~DFS_CTRL_DLL_RESET, DFS_CTRL(dfs->reg));
+
+ while (readl_relaxed(DFS_PORTSR(dfs->reg)) & (1 << (dfs->idx)))
+ ;
+
+ return 0;
+}
+
+static int clk_dfs_is_enabled(struct clk_hw *hw)
+{
+ struct clk_dfs *dfs = to_clk_dfs(hw);
+
+ /* Check if current DFS output port is locked */
+ if (readl_relaxed(DFS_PORTSR(dfs->reg)) & (1 << (dfs->idx)))
+ return 0;
+
+ return 1;
+}
+
+static const struct clk_ops clk_dfs_ops = {
+ .enable = clk_dfs_enable,
+ .disable = clk_dfs_disable,
+ .recalc_rate = clk_dfs_recalc_rate,
+ .round_rate = clk_dfs_round_rate,
+ .set_rate = clk_dfs_set_rate,
+ .is_enabled = clk_dfs_is_enabled,
+};
+
+struct clk *s32v234_clk_dfs(enum s32v234_plldig_type type, const char *name,
+ const char *parent_name, void __iomem *reg,
+ u8 idx, u32 mfn)
+{
+ struct clk_dfs *dfs;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ /* PERIPH and VIDEO PLL do not have DFS */
+ if (type == S32_PLLDIG_PERIPH || type == S32_PLLDIG_VIDEO)
+ return ERR_PTR(-EINVAL);
+
+ /* check if DFS index is valid for current pll */
+ if (idx >= get_pllx_dfs_nr(type))
+ return ERR_PTR(-EINVAL);
+
+ dfs = kzalloc(sizeof(*dfs), GFP_KERNEL);
+ if (!dfs)
+ return ERR_PTR(-ENOMEM);
+
+ dfs->reg = reg;
+ dfs->idx = idx;
+ dfs->mfn = mfn;
+ dfs->plltype = type;
+
+ init.name = name;
+ init.ops = &clk_dfs_ops;
+ init.flags = 0;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ dfs->hw.init = &init;
+
+ clk = clk_register(NULL, &dfs->hw);
+ if (IS_ERR(clk))
+ kfree(dfs);
+
+ return clk;
+}
diff --git a/drivers/clk/s32/s32v234/clk-plldig.c b/drivers/clk/s32/s32v234/clk-plldig.c
new file mode 100644
index 000000000000..6ed23974ee63
--- /dev/null
+++ b/drivers/clk/s32/s32v234/clk-plldig.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/err.h>
+#include "clk.h"
+
+/*
+ * struct clk_plldig - S32 PLLDIG clock
+ * @clk_hw: clock source
+ * @base: base address of PLL registers
+ * @plldv_mfd: multiplication loop factor divider
+ * @plldv_rfdphi: PHI reduced frequency divider
+ * @plldv_rfdphi1: PHI reduced frequency divider
+ *
+ * PLLDIG clock version 1, found on S32 series.
+ */
+struct clk_plldig {
+ struct clk_hw hw;
+ void __iomem *base;
+ enum s32v234_plldig_type type;
+ u32 plldv_mfd;
+ u32 pllfd_mfn;
+ u32 plldv_rfdphi;
+ u32 plldv_rfdphi1;
+};
+
+#define to_clk_plldig(_hw) container_of(_hw, struct clk_plldig, hw)
+
+static unsigned long get_pllx_max_vco_rate(enum s32v234_plldig_type plltype)
+{
+ switch (plltype) {
+ case S32_PLLDIG_PERIPH:
+ return PERIPHPLL_MAX_VCO_RATE;
+ default:
+ pr_warn("Unsupported PLL.\n");
+ return -EINVAL;
+ }
+}
+
+static unsigned long get_pllx_phiy_max_rate(enum s32v234_plldig_type plltype,
+ unsigned int phino)
+{
+ switch (plltype) {
+ case S32_PLLDIG_PERIPH:
+ switch (phino) {
+ case 0:
+ return PERIPHPLL_MAX_PHI0_MAX_RATE;
+ case 1:
+ return PERIPHPLL_MAX_PHI1_MAX_RATE;
+ default:
+ break;
+ }
+ break;
+ default:
+ pr_warn("Unsupported PLL.\n");
+ break;
+ }
+ return -EINVAL;
+}
+
+static int clk_plldig_prepare(struct clk_hw *hw)
+{
+ return 0;
+}
+
+static void clk_plldig_unprepare(struct clk_hw *hw)
+{
+}
+
+static unsigned long clk_plldig_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_plldig *pll = to_clk_plldig(hw);
+ u32 plldv = readl_relaxed(PLLDIG_PLLDV(pll->base));
+ u32 pllfd = readl_relaxed(PLLDIG_PLLFD(pll->base));
+ u32 prediv, mfd, mfn, vco;
+
+ prediv = (plldv & PLLDIG_PLLDV_PREDIV_MASK)
+ >> PLLDIG_PLLDV_PREDIV_OFFSET;
+ mfd = (plldv & PLLDIG_PLLDV_MFD_MASK);
+
+ mfn = (pllfd & PLLDIG_PLLFD_MFN_MASK);
+
+ if (prediv == 0)
+ prediv = 1;
+
+ /*
+ * This formula is from platform reference manual
+ * (Rev. 1, 6/2015), PLLDIG chapter.
+ */
+ vco = (parent_rate / prediv) * (mfd + mfn / 20480);
+
+ return vco;
+}
+
+static long clk_plldig_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_plldig *pll = to_clk_plldig(hw);
+ unsigned long max_allowed_rate = get_pllx_max_vco_rate(pll->type);
+
+ if (rate > max_allowed_rate)
+ rate = max_allowed_rate;
+ else if (rate < MIN_VCO_RATE)
+ rate = MIN_VCO_RATE;
+
+ return rate;
+}
+
+static int clk_plldig_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_plldig *pll = to_clk_plldig(hw);
+ u32 pllfd, prediv;
+
+ unsigned long max_allowed_rate = get_pllx_max_vco_rate(pll->type);
+ unsigned long phi0_max_rate = get_pllx_phiy_max_rate(pll->type, 0);
+ unsigned long phi1_max_rate = get_pllx_phiy_max_rate(pll->type, 1);
+
+ if (rate < MIN_VCO_RATE || rate > max_allowed_rate)
+ return -EINVAL;
+
+ if (((rate / pll->plldv_rfdphi) > phi0_max_rate) ||
+ ((rate / pll->plldv_rfdphi) > phi1_max_rate))
+ return -EINVAL;
+
+ pllfd = readl_relaxed(PLLDIG_PLLFD(pll->base));
+ prediv = (parent_rate / rate) *
+ (pll->plldv_mfd + pll->pllfd_mfn / 20480);
+
+ writel_relaxed(PLLDIG_PLLDV_RFDPHI1_SET(pll->plldv_rfdphi1) |
+ PLLDIG_PLLDV_RFDPHI_SET(pll->plldv_rfdphi) |
+ PLLDIG_PLLDV_PREDIV_SET(prediv) |
+ PLLDIG_PLLDV_MFD_SET(pll->plldv_mfd),
+ PLLDIG_PLLDV(pll->base));
+
+ writel_relaxed(pllfd | PLLDIG_PLLFD_MFN_SET(pll->pllfd_mfn),
+ PLLDIG_PLLFD(pll->base));
+
+ /*
+ * To be implemented the wait_lock or an equivalent state
+ * return clk_plldig_wait_lock(pll);
+ */
+ return 0;
+}
+
+static const struct clk_ops clk_plldig_ops = {
+ .prepare = clk_plldig_prepare,
+ .unprepare = clk_plldig_unprepare,
+ .recalc_rate = clk_plldig_recalc_rate,
+ .round_rate = clk_plldig_round_rate,
+ .set_rate = clk_plldig_set_rate,
+};
+
+struct clk *s32v234_clk_plldig_phi(enum s32v234_plldig_type type,
+ const char *name, const char *parent,
+ void __iomem *base, u32 phi)
+{
+ u32 plldv, rfd_phi;
+
+ if (!base)
+ return ERR_PTR(-ENOMEM);
+
+ plldv = readl_relaxed(PLLDIG_PLLDV(base));
+
+ switch (phi) {
+ /* PHI0 */
+ case 0:
+ rfd_phi = (plldv & PLLDIG_PLLDV_RFDPHI_MASK)
+ >> PLLDIG_PLLDV_RFDPHI_OFFSET;
+ break;
+ /* PHI1 */
+ case 1:
+ rfd_phi = (plldv & PLLDIG_PLLDV_RFDPHI1_MASK)
+ >> PLLDIG_PLLDV_RFDPHI1_OFFSET;
+
+ if (rfd_phi == 0)
+ rfd_phi = 1;
+
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+
+ return clk_register_fixed_factor(NULL, name, parent,
+ CLK_SET_RATE_PARENT, 1, rfd_phi);
+}
+
+struct clk *s32v234_clk_plldig(enum s32v234_plldig_type type, const char *name,
+ const char *parent_name, void __iomem *base,
+ u32 plldv_mfd, u32 pllfd_mfn,
+ u32 plldv_rfdphi, u32 plldv_rfdphi1)
+{
+ struct clk_plldig *pll;
+ const struct clk_ops *ops;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ if (plldv_rfdphi > PLLDIG_PLLDV_RFDPHI_MAXVALUE)
+ return ERR_PTR(-EINVAL);
+
+ if (plldv_rfdphi1 > PLLDIG_PLLDV_RFDPHI1_MAXVALUE)
+ return ERR_PTR(-EINVAL);
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ ops = &clk_plldig_ops;
+
+ pll->base = base;
+ pll->type = type;
+ pll->plldv_mfd = plldv_mfd;
+ pll->pllfd_mfn = pllfd_mfn;
+ pll->plldv_rfdphi = plldv_rfdphi;
+ pll->plldv_rfdphi1 = plldv_rfdphi1;
+
+ init.name = name;
+ init.ops = ops;
+ init.flags = 0;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ pll->hw.init = &init;
+
+ clk = clk_register(NULL, &pll->hw);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
diff --git a/drivers/clk/s32/s32v234/clk.c b/drivers/clk/s32/s32v234/clk.c
new file mode 100644
index 000000000000..ad88c6b45c6b
--- /dev/null
+++ b/drivers/clk/s32/s32v234/clk.c
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ */
+
+#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <dt-bindings/clock/s32v234-clock.h>
+
+#include "clk.h"
+
+static void __iomem *mc_cgm0_base;
+static void __iomem *mc_cgm1_base;
+static void __iomem *mc_cgm2_base;
+static void __iomem *mc_cgm3_base;
+static void __iomem *mc_me_base;
+static void __iomem *src_base;
+
+DEFINE_SPINLOCK(s32v234_lock);
+
+/* sources for multiplexer clocks, this is used multiple times */
+PNAME(osc_sels) = {"firc", "fxosc", };
+
+PNAME(sys_sels) = {"firc", "fxosc", "armpll_dfs0", };
+
+PNAME(can_sels) = {"firc", "fxosc", "dummy",
+ "periphpll_phi0_div5", };
+
+PNAME(lin_sels) = {"firc", "fxosc", "dummy",
+ "periphpll_phi0_div3", "dummy", "dummy",
+ "dummy", "dummy", "sys6",};
+
+PNAME(sdhc_sels) = {"firc", "fxosc", "dummy", "dummy",
+ "enetpll_dfs3",};
+
+PNAME(enet_sels) = {"firc", "fxosc", "dummy",
+ "dummy", "enetpll_phi0",};
+
+PNAME(enet_time_sels) = {"firc", "fxosc", "dummy",
+ "dummy", "enetpll_phi0",};
+
+static struct clk *clk[S32V234_CLK_END];
+static struct clk_onecell_data clk_data;
+
+static void __init s32v234_clocks_init(struct device_node *mc_cgm0_node)
+{
+ struct device_node *np;
+
+ clk[S32V234_CLK_DUMMY] = s32_clk_fixed("dummy", 0);
+ clk[S32V234_CLK_FXOSC] = s32_obtain_fixed_clock("fxosc", 0);
+ clk[S32V234_CLK_FIRC] = s32_obtain_fixed_clock("firc", 0);
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-mc_me");
+ mc_me_base = of_iomap(np, 0);
+ if (WARN_ON(!mc_me_base))
+ return;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-src");
+ src_base = of_iomap(np, 0);
+ if (WARN_ON(!src_base))
+ return;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-mc_cgm1");
+ mc_cgm1_base = of_iomap(np, 0);
+ if (WARN_ON(!mc_cgm1_base))
+ return;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-mc_cgm2");
+ mc_cgm2_base = of_iomap(np, 0);
+ if (WARN_ON(!mc_cgm2_base))
+ return;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-mc_cgm3");
+ mc_cgm3_base = of_iomap(np, 0);
+ if (WARN_ON(!mc_cgm3_base))
+ return;
+
+ np = mc_cgm0_node;
+ mc_cgm0_base = of_iomap(np, 0);
+ if (WARN_ON(!mc_cgm0_base))
+ return;
+
+ enable_cpumodes_onperipheralconfig(mc_me_base, MC_ME_RUN_PCn_DRUN |
+ MC_ME_RUN_PCn_RUN0 |
+ MC_ME_RUN_PCn_RUN1 |
+ MC_ME_RUN_PCn_RUN2 |
+ MC_ME_RUN_PCn_RUN3,
+ 0);
+
+ /* turn on XOSC and FIRC */
+ enable_clocks_sources(MC_ME_MODE_MC_MVRON, MC_ME_MODE_MC_XOSCON |
+ MC_ME_MODE_MC_FIRCON,
+ MC_ME_RUNn_MC(mc_me_base, 0));
+
+ /* transition the core to RUN0 mode */
+ entry_to_target_mode(mc_me_base, MC_ME_MCTL_RUN0);
+
+ clk[S32V234_CLK_ARMPLL_SRC_SEL] = s32_clk_mux("armpll_sel",
+ SRC_GPR1, SRC_GPR1_ARMPLL_SRC_SEL_OFFSET,
+ SRC_GPR1_XPLL_SRC_SEL_SIZE,
+ osc_sels, ARRAY_SIZE(osc_sels), &s32v234_lock);
+
+ clk[S32V234_CLK_PERIPHPLL_SRC_SEL] = s32_clk_mux("periphpll_sel",
+ SRC_GPR1, SRC_GPR1_PERIPHPLL_SRC_SEL_OFFSET,
+ SRC_GPR1_XPLL_SRC_SEL_SIZE,
+ osc_sels, ARRAY_SIZE(osc_sels), &s32v234_lock);
+
+ clk[S32V234_CLK_ENETPLL_SRC_SEL] = s32_clk_mux("enetpll_sel",
+ SRC_GPR1, SRC_GPR1_ENETPLL_SRC_SEL_OFFSET,
+ SRC_GPR1_XPLL_SRC_SEL_SIZE,
+ osc_sels, ARRAY_SIZE(osc_sels), &s32v234_lock);
+
+ /* ARM_PLL */
+ clk[S32V234_CLK_ARMPLL_VCO] = s32v234_clk_plldig(S32_PLLDIG_ARM,
+ "armpll_vco", "armpll_sel", ARMPLL_PLLDIG(mc_cgm0_base),
+ ARMPLL_PLLDIG_PLLDV_MFD, ARMPLL_PLLDIG_PLLDV_MFN,
+ ARMPLL_PLLDIG_PLLDV_RFDPHI0, ARMPLL_PLLDIG_PLLDV_RFDPHI1);
+
+ clk[S32V234_CLK_ARMPLL_PHI0] = s32v234_clk_plldig_phi(S32_PLLDIG_ARM,
+ "armpll_phi0", "armpll_vco",
+ ARMPLL_PLLDIG(mc_cgm0_base), 0);
+
+ clk[S32V234_CLK_ARMPLL_PHI1] = s32v234_clk_plldig_phi(S32_PLLDIG_ARM,
+ "armpll_phi1", "armpll_vco",
+ ARMPLL_PLLDIG(mc_cgm0_base), 1);
+
+ clk[S32V234_CLK_ARMPLL_DFS0] = s32v234_clk_dfs(S32_PLLDIG_ARM,
+ "armpll_dfs0", "armpll_phi1",
+ ARMPLL_PLLDIG_DFS(mc_cgm0_base), 0,
+ ARMPLL_PLLDIG_DFS0_MFN);
+
+ clk[S32V234_CLK_ARMPLL_DFS1] = s32v234_clk_dfs(S32_PLLDIG_ARM,
+ "armpll_dfs1", "armpll_phi1",
+ ARMPLL_PLLDIG_DFS(mc_cgm0_base), 1,
+ ARMPLL_PLLDIG_DFS1_MFN);
+
+ clk[S32V234_CLK_ARMPLL_DFS2] = s32v234_clk_dfs(S32_PLLDIG_ARM,
+ "armpll_dfs2", "armpll_phi1",
+ ARMPLL_PLLDIG_DFS(mc_cgm0_base), 2,
+ ARMPLL_PLLDIG_DFS2_MFN);
+
+ clk[S32V234_CLK_SYS_SEL] = s32_clk_mux("sys_sel",
+ MC_ME_RUNn_MC(mc_me_base, 0),
+ MC_ME_MODE_MC_SYSCLK_OFFSET,
+ MC_ME_MODE_MC_SYSCLK_SIZE,
+ sys_sels, ARRAY_SIZE(sys_sels), &s32v234_lock);
+
+ clk[S32V234_CLK_SYS3] = s32_clk_divider("sys3", "sys_sel",
+ CGM_SC_DCn(mc_cgm0_base, 0), MC_CGM_SC_DCn_PREDIV_OFFSET,
+ MC_CGM_SC_DCn_PREDIV_SIZE, &s32v234_lock);
+
+ clk[S32V234_CLK_SYS6] = s32_clk_divider("sys6", "sys_sel",
+ CGM_SC_DCn(mc_cgm0_base, 1), MC_CGM_SC_DCn_PREDIV_OFFSET,
+ MC_CGM_SC_DCn_PREDIV_SIZE, &s32v234_lock);
+
+ clk[S32V234_CLK_SYS6_DIV2] = s32_clk_divider("sys6_div2", "sys_sel",
+ CGM_SC_DCn(mc_cgm0_base, 2), MC_CGM_SC_DCn_PREDIV_OFFSET,
+ MC_CGM_SC_DCn_PREDIV_SIZE, &s32v234_lock);
+
+ /* PERIPH_PLL */
+ clk[S32V234_CLK_PERIPHPLL_VCO] = s32v234_clk_plldig(S32_PLLDIG_PERIPH,
+ "periphpll_vco", "periphpll_sel",
+ PERIPHPLL_PLLDIG(mc_cgm0_base),
+ PERIPHPLL_PLLDIG_PLLDV_MFD, PERIPHPLL_PLLDIG_PLLDV_MFN,
+ PERIPHPLL_PLLDIG_PLLDV_RFDPHI0,
+ PERIPHPLL_PLLDIG_PLLDV_RFDPHI1);
+
+ clk[S32V234_CLK_PERIPHPLL_PHI0] =
+ s32v234_clk_plldig_phi(S32_PLLDIG_PERIPH,
+ "periphpll_phi0", "periphpll_vco",
+ PERIPHPLL_PLLDIG(mc_cgm0_base), 0);
+
+ clk[S32V234_CLK_PERIPHPLL_PHI1] =
+ s32v234_clk_plldig_phi(S32_PLLDIG_PERIPH,
+ "periphpll_phi1", "periphpll_vco",
+ PERIPHPLL_PLLDIG(mc_cgm0_base), 1);
+
+ clk[S32V234_CLK_PERIPHPLL_PHI0_DIV3] = s32_clk_fixed_factor(
+ "periphpll_phi0_div3", "periphpll_phi0", 1, 3);
+
+ clk[S32V234_CLK_PERIPHPLL_PHI0_DIV5] = s32_clk_fixed_factor(
+ "periphpll_phi0_div5", "periphpll_phi0", 1, 5);
+
+ clk[S32V234_CLK_CAN_SEL] = s32_clk_mux("can_sel",
+ CGM_ACn_SC(mc_cgm0_base, 6),
+ MC_CGM_ACn_SEL_OFFSET,
+ MC_CGM_ACn_SEL_SIZE,
+ can_sels, ARRAY_SIZE(can_sels), &s32v234_lock);
+
+ /* CAN Clock */
+ clk[S32V234_CLK_CAN] = s32_clk_divider("can", "can_sel",
+ CGM_ACn_DCm(mc_cgm0_base, 6, 0),
+ MC_CGM_ACn_DCm_PREDIV_OFFSET,
+ MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock);
+
+ /* Lin Clock */
+ clk[S32V234_CLK_LIN_SEL] = s32_clk_mux("lin_sel",
+ CGM_ACn_SC(mc_cgm0_base, 3),
+ MC_CGM_ACn_SEL_OFFSET,
+ MC_CGM_ACn_SEL_SIZE,
+ lin_sels, ARRAY_SIZE(lin_sels), &s32v234_lock);
+
+ clk[S32V234_CLK_LIN] = s32_clk_divider("lin", "lin_sel",
+ CGM_ACn_DCm(mc_cgm0_base, 3, 0),
+ MC_CGM_ACn_DCm_PREDIV_OFFSET,
+ MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock);
+
+ clk[S32V234_CLK_LIN_IPG] = s32_clk_fixed_factor("lin_ipg",
+ "lin", 1, 2);
+
+ /* enable PERIPHPLL */
+ enable_clocks_sources(0, MC_ME_MODE_MC_PERIPHPLL,
+ MC_ME_RUNn_MC(mc_me_base, 0));
+
+ /* ENET_PLL */
+ clk[S32V234_CLK_ENETPLL_VCO] = s32v234_clk_plldig(S32_PLLDIG_ENET,
+ "enetpll_vco", "enetpll_sel", ENETPLL_PLLDIG(mc_cgm0_base),
+ ENETPLL_PLLDIG_PLLDV_MFD, ENETPLL_PLLDIG_PLLDV_MFN,
+ ENETPLL_PLLDIG_PLLDV_RFDPHI0, ENETPLL_PLLDIG_PLLDV_RFDPHI1);
+
+ clk[S32V234_CLK_ENETPLL_PHI0] = s32v234_clk_plldig_phi(S32_PLLDIG_ENET,
+ "enetpll_phi0", "enetpll_vco",
+ ENETPLL_PLLDIG(mc_cgm0_base), 0);
+
+ clk[S32V234_CLK_ENETPLL_PHI1] = s32v234_clk_plldig_phi(S32_PLLDIG_ENET,
+ "enetpll_phi1", "enetpll_vco",
+ ENETPLL_PLLDIG(mc_cgm0_base), 1);
+
+ clk[S32V234_CLK_ENETPLL_DFS0] = s32v234_clk_dfs(S32_PLLDIG_ENET,
+ "enetpll_dfs0", "enetpll_phi1",
+ ENETPLL_PLLDIG_DFS(mc_cgm0_base), 0,
+ ENETPLL_PLLDIG_DFS0_MFN);
+
+ clk[S32V234_CLK_ENETPLL_DFS1] = s32v234_clk_dfs(S32_PLLDIG_ENET,
+ "enetpll_dfs1", "enetpll_phi1",
+ ENETPLL_PLLDIG_DFS(mc_cgm0_base), 1,
+ ENETPLL_PLLDIG_DFS1_MFN);
+
+ clk[S32V234_CLK_ENETPLL_DFS2] = s32v234_clk_dfs(S32_PLLDIG_ENET,
+ "enetpll_dfs2", "enetpll_phi1",
+ ENETPLL_PLLDIG_DFS(mc_cgm0_base), 2,
+ ENETPLL_PLLDIG_DFS2_MFN);
+
+ clk[S32V234_CLK_ENETPLL_DFS3] = s32v234_clk_dfs(S32_PLLDIG_ENET,
+ "enetpll_dfs3", "enetpll_phi1",
+ ENETPLL_PLLDIG_DFS(mc_cgm0_base), 3,
+ ENETPLL_PLLDIG_DFS3_MFN);
+
+ /* ENET Clock */
+ clk[S32V234_CLK_ENET_SEL] = s32_clk_mux("enet_sel",
+ CGM_ACn_SC(mc_cgm2_base, 2),
+ MC_CGM_ACn_SEL_OFFSET,
+ MC_CGM_ACn_SEL_SIZE,
+ enet_sels, ARRAY_SIZE(enet_sels), &s32v234_lock);
+
+ clk[S32V234_CLK_ENET_TIME_SEL] = s32_clk_mux("enet_time_sel",
+ CGM_ACn_SC(mc_cgm0_base, 7),
+ MC_CGM_ACn_SEL_OFFSET,
+ MC_CGM_ACn_SEL_SIZE,
+ enet_time_sels, ARRAY_SIZE(enet_time_sels), &s32v234_lock);
+
+ clk[S32V234_CLK_ENET] = s32_clk_divider("enet", "enet_sel",
+ CGM_ACn_DCm(mc_cgm2_base, 2, 0),
+ MC_CGM_ACn_DCm_PREDIV_OFFSET,
+ MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock);
+
+ clk[S32V234_CLK_ENET_TIME] = s32_clk_divider("enet_time",
+ "enet_time_sel",
+ CGM_ACn_DCm(mc_cgm0_base, 7, 1),
+ MC_CGM_ACn_DCm_PREDIV_OFFSET,
+ MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock);
+
+ /* SDHC Clock */
+ clk[S32V234_CLK_SDHC_SEL] = s32_clk_mux("sdhc_sel",
+ CGM_ACn_SC(mc_cgm0_base, 15),
+ MC_CGM_ACn_SEL_OFFSET,
+ MC_CGM_ACn_SEL_SIZE,
+ sdhc_sels, ARRAY_SIZE(sdhc_sels), &s32v234_lock);
+
+ clk[S32V234_CLK_SDHC] = s32_clk_divider("sdhc", "sdhc_sel",
+ CGM_ACn_DCm(mc_cgm0_base, 15, 0),
+ MC_CGM_ACn_DCm_PREDIV_OFFSET,
+ MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock);
+
+ /* set the system clock */
+ enable_sysclock(MC_ME_MODE_MC_SYSCLK(0x2),
+ MC_ME_RUNn_MC(mc_me_base, 0));
+
+ /* transition the core to RUN0 mode */
+ entry_to_target_mode(mc_me_base, MC_ME_MCTL_RUN0);
+
+ /* Add the clocks to provider list */
+ clk_data.clks = clk;
+ clk_data.clk_num = ARRAY_SIZE(clk);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+
+CLK_OF_DECLARE(S32V234, "fsl,s32v234-mc_cgm0", s32v234_clocks_init);
diff --git a/drivers/clk/s32/s32v234/clk.h b/drivers/clk/s32/s32v234/clk.h
new file mode 100644
index 000000000000..82a222483394
--- /dev/null
+++ b/drivers/clk/s32/s32v234/clk.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ */
+
+#ifndef __MACH_S32V234_CLK_H
+#define __MACH_S32V234_CLK_H
+
+#include <linux/spinlock.h>
+#include <linux/clk-provider.h>
+#include "mc_cgm.h"
+#include "mc_me.h"
+#include "pll.h"
+#include "src.h"
+#include "dfs.h"
+#include "../clk.h"
+
+struct clk *s32v234_clk_plldig(enum s32v234_plldig_type type, const char *name,
+ const char *parent_name, void __iomem *base,
+ u32 plldv_mfd, u32 plldv_mfn,
+ u32 plldv_rfdphi, u32 plldv_rfdphi1);
+
+struct clk *s32v234_clk_plldig_phi(enum s32v234_plldig_type type,
+ const char *name, const char *parent,
+ void __iomem *base, u32 phi);
+
+struct clk *s32v234_clk_dfs(enum s32v234_plldig_type type, const char *name,
+ const char *parent_name,
+ void __iomem *reg, u8 idx, u32 mfn);
+#endif
diff --git a/drivers/clk/s32/s32v234/dfs.h b/drivers/clk/s32/s32v234/dfs.h
new file mode 100644
index 000000000000..be3104f7ae51
--- /dev/null
+++ b/drivers/clk/s32/s32v234/dfs.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef _DFS_S32V234_H
+#define _DFS_S32V234_H
+
+/* DFS Control Register (DFS_CTRL) */
+#define DFS_CTRL(base) ((base) + 0x00000018)
+#define DFS_CTRL_DLL_LOLIE (1 << 0)
+#define DFS_CTRL_DLL_RESET (1 << 1)
+
+/* DFS Port Status (DFS_PORTSR) */
+#define DFS_PORTSR(base) ((base) + 0x0000000C)
+#define DFS_PORTSR_MASK (0x0000000F)
+#define DFS_PORTSR_OFFSET (28)
+
+/* DFS Port Reset Register (DFS_PORTRESET) */
+#define DFS_PORTRESET(base) ((base) + 0x00000014)
+#define DFS_PORTRESET_PORTRESET_SET(val) \
+ (DFS_PORTRESET_PORTRESET_MASK | \
+ (((val) & DFS_PORTRESET_PORTRESET_MAXVAL) \
+ << DFS_PORTRESET_PORTRESET_OFFSET))
+#define DFS_PORTRESET_PORTRESET_MAXVAL (0xF)
+#define DFS_PORTRESET_PORTRESET_MASK (0x0000000F)
+#define DFS_PORTRESET_PORTRESET_OFFSET (28)
+
+/* DFS Divide Register Portn (DFS_DVPORTn) */
+#define DFS_DVPORTn(base, n) ((base) + (0x0000001C + \
+ ((n) * sizeof(u32))))
+#define DFS_DVPORTn_MFI_SET(val) (DFS_DVPORTn_MFI_MASK & \
+ (((val) & DFS_DVPORTn_MFI_MAXVAL) \
+ << DFS_DVPORTn_MFI_OFFSET))
+#define DFS_DVPORTn_MFN_SET(val) (DFS_DVPORTn_MFN_MASK & \
+ (((val) & DFS_DVPORTn_MFN_MAXVAL) \
+ << DFS_DVPORTn_MFN_OFFSET))
+#define DFS_DVPORTn_MFI_MASK (0x0000FF00)
+#define DFS_DVPORTn_MFN_MASK (0x000000FF)
+#define DFS_DVPORTn_MFI_MAXVAL (0xFF)
+#define DFS_DVPORTn_MFN_MAXVAL (0xFF)
+#define DFS_DVPORTn_MFI_OFFSET (8)
+#define DFS_DVPORTn_MFN_OFFSET (0)
+#define DFS_MAXNUMBER (4)
+
+/*
+ * Naming convention for PLL:
+ * ARMPLL - PLL0
+ * PERIPHPLL - PLL1
+ * ENETPLL - PLL2
+ * DDRPLL - PLL3
+ * VIDEOPLL - PLL4
+ */
+
+/* The max values for PLL DFS is in Hz */
+/* ARMPLL */
+#define ARMPLL_DFS0_MAX_RATE (266000000)
+#define ARMPLL_DFS1_MAX_RATE (600000000)
+#define ARMPLL_DFS2_MAX_RATE (600000000)
+/* ENETPLL */
+#define ENETPLL_DFS0_MAX_RATE (350000000)
+#define ENETPLL_DFS1_MAX_RATE (350000000)
+#define ENETPLL_DFS2_MAX_RATE (416000000)
+#define ENETPLL_DFS3_MAX_RATE (104000000)
+/* DDRPLL */
+#define DDRPLL_DFS0_MAX_RATE (500000000)
+#define DDRPLL_DFS1_MAX_RATE (500000000)
+#define DDRPLL_DFS2_MAX_RATE (350000000)
+
+#define ARMPLL_DFS_NR (3)
+#define ENETPLL_DFS_NR (4)
+#define DDRPLL_DFS_NR (3)
+
+#endif
diff --git a/drivers/clk/s32/s32v234/mc_cgm.h b/drivers/clk/s32/s32v234/mc_cgm.h
new file mode 100644
index 000000000000..aeac68771890
--- /dev/null
+++ b/drivers/clk/s32/s32v234/mc_cgm.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright (C) 2017 NXP
+ */
+#ifndef _MC_CGM_H
+#define _MC_CGM_H
+
+#define ARMPLL_PLLDIG(mc_cgm) (mc_cgm)
+#define ARMPLL_PLLDIG_DFS(mc_cgm) ((mc_cgm) + 0x40)
+#define ARMPLL_PLLDIG_PLLDV_MFD (50)
+#define ARMPLL_PLLDIG_PLLDV_MFN (0)
+#define ARMPLL_PLLDIG_PLLDV_RFDPHI0 (1)
+#define ARMPLL_PLLDIG_PLLDV_RFDPHI1 (1)
+#define ARMPLL_PLLDIG_DFS0_MFN (195)
+#define ARMPLL_PLLDIG_DFS1_MFN (171)
+#define ARMPLL_PLLDIG_DFS2_MFN (171)
+
+#define PERIPHPLL_PLLDIG(mc_cgm) ((mc_cgm) + 0x80)
+#define PERIPHPLL_PLLDIG_PLLDV_MFD (30)
+#define PERIPHPLL_PLLDIG_PLLDV_MFN (0)
+#define PERIPHPLL_PLLDIG_PLLDV_RFDPHI0 (0x1)
+#define PERIPHPLL_PLLDIG_PLLDV_RFDPHI1 (0x1)
+
+#define ENETPLL_PLLDIG(mc_cgm) ((mc_cgm) + 0x100)
+#define ENETPLL_PLLDIG_DFS(mc_cgm) ((mc_cgm) + 0x100 + 0x40)
+#define ENETPLL_PLLDIG_PLLDV_MFD (50)
+#define ENETPLL_PLLDIG_PLLDV_MFN (0)
+#define ENETPLL_PLLDIG_PLLDV_RFDPHI0 (0x1)
+#define ENETPLL_PLLDIG_PLLDV_RFDPHI1 (0x1)
+#define ENETPLL_PLLDIG_DFS0_MFN (220)
+#define ENETPLL_PLLDIG_DFS1_MFN (220)
+#define ENETPLL_PLLDIG_DFS2_MFN (33)
+#define ENETPLL_PLLDIG_DFS3_MFN (1)
+
+/* MC_CGM_SC_SS */
+#define CGM_SC_SS(mc_cgm) (((mc_cgm) + 0x7E4))
+
+/* MC_CGM_SC_DCn */
+#define CGM_SC_DCn(mc_cgm, dc) (((mc_cgm) + 0x7E8) + ((dc) * 0x4))
+
+#define MC_CGM_SC_DCn_PREDIV_OFFSET (16)
+#define MC_CGM_SC_DCn_PREDIV_SIZE (3)
+#define MC_CGM_SC_DCn_DE (1 << 31)
+#define MC_CGM_SC_SEL_OFFSET (24)
+#define MC_CGM_SC_SEL_SIZE (4)
+
+/* MC_CGM_ACn_DCm */
+#define CGM_ACn_DCm(mc_cgm, ac, dc) (((mc_cgm) + 0x808) + ((ac) * 0x20)\
+ + ((dc) * 0x4))
+
+#define MC_CGM_ACn_DCm_PREDIV(val) (MC_CGM_ACn_DCm_PREDIV_MASK & \
+ ((val) \
+ << MC_CGM_ACn_DCm_PREDIV_OFFSET))
+#define MC_CGM_ACn_DCm_PREDIV_MASK (0x001F0000)
+#define MC_CGM_ACn_DCm_PREDIV_OFFSET (16)
+#define MC_CGM_ACn_DCm_PREDIV_SIZE (5)
+#define MC_CGM_ACn_DCm_DE (1 << 31)
+
+/* MC_CGM_ACn_SC/MC_CGM_ACn_SS */
+#define CGM_ACn_SC(mc_cgm, ac) (((mc_cgm) + 0x800) + ((ac) * 0x20))
+#define CGM_ACn_SS(mc_cgm, ac) (((mc_cgm) + 0x804) + ((ac) * 0x24))
+#define MC_CGM_ACn_SEL_MASK (0x07000000)
+#define MC_CGM_ACn_SEL_SET(source) (MC_CGM_ACn_SEL_MASK & \
+ (((source) & 0x7) \
+ << MC_CGM_ACn_SEL_OFFSET))
+#define MC_CGM_ACn_SEL_OFFSET (24)
+#define MC_CGM_ACn_SEL_SIZE (4)
+
+#endif
diff --git a/drivers/clk/s32/s32v234/mc_me.h b/drivers/clk/s32/s32v234/mc_me.h
new file mode 100644
index 000000000000..718f1d1a0c30
--- /dev/null
+++ b/drivers/clk/s32/s32v234/mc_me.h
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright (C) 2017 NXP
+ */
+
+#ifndef _MC_ME_H
+#define _MC_ME_H
+
+/* MC_ME registers definitions */
+/* MC_ME_GS */
+ #define MC_ME_GS(mc_me) ((mc_me) + 0x00000000)
+
+/* MC_ME_MCTL */
+#define MC_ME_MCTL(mc_me) ((mc_me) + 0x00000004)
+#define MC_ME_MCTL_RESET (0x0 << 28)
+#define MC_ME_MCTL_TEST (0x1 << 28)
+#define MC_ME_MCTL_DRUN (0x3 << 28)
+#define MC_ME_MCTL_RUN0 (0x4 << 28)
+#define MC_ME_MCTL_RUN1 (0x5 << 28)
+#define MC_ME_MCTL_RUN2 (0x6 << 28)
+#define MC_ME_MCTL_RUN3 (0x7 << 28)
+
+#define MC_ME_GS_S_MTRANS (1 << 27)
+
+#define MC_ME_MCTL_KEY (0x00005AF0)
+#define MC_ME_MCTL_INVERTEDKEY (0x0000A50F)
+
+/*
+ * MC_ME_RESET_MC/MC_ME_TEST_MC
+ * MC_ME_DRUN_MC
+ * MC_ME_RUNn_MC
+ */
+#define MC_ME_RESET_MC(mc_me) ((mc_me) + 0x00000020)
+#define MC_ME_TEST_MC(mc_me) ((mc_me) + 0x00000024)
+#define MC_ME_DRUN_MC(mc_me) ((mc_me) + 0x0000002C)
+#define MC_ME_RUNn_MC(mc_me, n) ((mc_me) + 0x00000030 + 0x4 * (n))
+#define MC_ME_MODE_MC_SYSCLK_OFFSET (0)
+#define MC_ME_MODE_MC_SYSCLK_SIZE (0x3)
+#define MC_ME_MODE_MC_SYSCLK(val) (MC_ME_MODE_MC_SYSCLK_MASK & (val))
+#define MC_ME_MODE_MC_SYSCLK_MASK (0x0000000F)
+#define MC_ME_MODE_MC_FIRCON (1 << 4)
+#define MC_ME_MODE_MC_XOSCON (1 << 5)
+#define MC_ME_MODE_MC_ARMPLL (1 << 6)
+#define MC_ME_MODE_MC_PERIPHPLL (1 << 7)
+#define MC_ME_MODE_MC_ENETPLL (1 << 8)
+#define MC_ME_MODE_MC_DDRPLL (1 << 9)
+#define MC_ME_MODE_MC_VIDEOPLL (1 << 10)
+#define MC_ME_MODE_MC_MVRON (1 << 20)
+
+/* MC_ME_DRUN_SEC_CC_I */
+#define MC_ME_DRUN_SEC_CC_I(mc_me) ((mc_me) + 0x260)
+/* MC_ME_RUNn_SEC_CC_I */
+#define MC_ME_RUNn_SEC_CC_I(mc_me, n) ((mc_me) + 0x270 + (n) * 0x10)
+#define MC_ME_MODE_SEC_CC_I_SYSCLK1_OFFSET (4)
+#define MC_ME_MODE_SEC_CC_I_SYSCLK2_OFFSET (8)
+#define MC_ME_MODE_SEC_CC_I_SYSCLK3_OFFSET (12)
+/* Consider only the defined clocks */
+#define MC_ME_MODE_SEC_CC_I_SYSCLK1_SIZE (0x3)
+#define MC_ME_MODE_SEC_CC_I_SYSCLK2_SIZE (0x3)
+#define MC_ME_MODE_SEC_CC_I_SYSCLK3_SIZE (0x3)
+
+/* MC_ME_RUN_PCn */
+#define MC_ME_RUN_PCn(mc_me, n) (mc_me + 0x00000080 + 0x4 * (n))
+
+#define MC_ME_RUN_PCn_MAX_IDX (7)
+#define MC_ME_RUN_PCn_RESET (1 << 0)
+#define MC_ME_RUN_PCn_TEST (1 << 1)
+#define MC_ME_RUN_PCn_DRUN (1 << 3)
+#define MC_ME_RUN_PCn_RUN0 (1 << 4)
+#define MC_ME_RUN_PCn_RUN1 (1 << 5)
+#define MC_ME_RUN_PCn_RUN2 (1 << 6)
+#define MC_ME_RUN_PCn_RUN3 (1 << 7)
+
+#define MC_ME_PCTLn(mc_me, n) (mc_me + 0xC0 + 4 * (n >> 2) + \
+ (3 - (n) % 4))
+
+static inline void entry_to_target_mode(void __iomem *mc_me, u32 mode)
+{
+ writel_relaxed(mode | MC_ME_MCTL_KEY, MC_ME_MCTL(mc_me));
+ writel_relaxed(mode | MC_ME_MCTL_INVERTEDKEY, MC_ME_MCTL(mc_me));
+ while ((readl_relaxed(MC_ME_GS(mc_me)) &
+ MC_ME_GS_S_MTRANS) != 0x00000000)
+ ;
+}
+
+static inline void enable_cpumodes_onperipheralconfig(void __iomem *mc_me,
+ u32 modes, u32 run_pc_idx)
+{
+ WARN_ON(run_pc_idx > MC_ME_RUN_PCn_MAX_IDX);
+ if (run_pc_idx > MC_ME_RUN_PCn_MAX_IDX)
+ return;
+
+ writel_relaxed(modes, MC_ME_RUN_PCn(mc_me, run_pc_idx));
+}
+
+static inline void enable_clocks_sources(u32 flags, u32 clks,
+ void __iomem *xrun_mc_addr)
+{
+ writel_relaxed(readl_relaxed(xrun_mc_addr) | flags | clks,
+ xrun_mc_addr);
+}
+
+static inline void enable_sysclock(u32 clk, void __iomem *xrun_mc_addr)
+{
+ writel_relaxed(readl_relaxed(xrun_mc_addr) & clk,
+ xrun_mc_addr);
+}
+
+#endif
diff --git a/drivers/clk/s32/s32v234/pll.h b/drivers/clk/s32/s32v234/pll.h
new file mode 100644
index 000000000000..b7bcc50f0a22
--- /dev/null
+++ b/drivers/clk/s32/s32v234/pll.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright (C) 2017-2018 NXP
+ */
+#ifndef _PLL_S32V234_H
+#define _PLL_S32V234_H
+
+/* PLLDIG PLL Divider Register (PLLDIG_PLLDV) */
+#define PLLDIG_PLLDV(base) ((base) + 0x00000028)
+#define PLLDIG_PLLDV_MFD_SET(val) (PLLDIG_PLLDV_MFD_MASK & (val))
+#define PLLDIG_PLLDV_MFD_MASK (0x000000FF)
+
+#define PLLDIG_PLLDV_RFDPHI_SET(val) (PLLDIG_PLLDV_RFDPHI_MASK & \
+ (((val) & \
+ PLLDIG_PLLDV_RFDPHI_MAXVALUE) \
+ << PLLDIG_PLLDV_RFDPHI_OFFSET))
+#define PLLDIG_PLLDV_RFDPHI_MASK (0x003F0000)
+#define PLLDIG_PLLDV_RFDPHI_MAXVALUE (0x3F)
+
+#define PLLDIG_PLLDV_RFDPHI_OFFSET (16)
+
+#define PLLDIG_PLLDV_RFDPHI1_SET(val) (PLLDIG_PLLDV_RFDPHI1_MASK & \
+ (((val) & \
+ PLLDIG_PLLDV_RFDPHI1_MAXVALUE) \
+ << PLLDIG_PLLDV_RFDPHI1_OFFSET))
+#define PLLDIG_PLLDV_RFDPHI1_MASK (0x7E000000)
+#define PLLDIG_PLLDV_RFDPHI1_MAXVALUE (0x3F)
+#define PLLDIG_PLLDV_RFDPHI1_OFFSET (25)
+
+#define PLLDIG_PLLDV_PREDIV_SET(val) (PLLDIG_PLLDV_PREDIV_MASK & \
+ (((val) & \
+ PLLDIG_PLLDV_PREDIV_MAXVALUE) \
+ << PLLDIG_PLLDV_PREDIV_OFFSET))
+#define PLLDIG_PLLDV_PREDIV_MASK (0x00007000)
+#define PLLDIG_PLLDV_PREDIV_MAXVALUE (0x7)
+#define PLLDIG_PLLDV_PREDIV_OFFSET (12)
+
+/* PLLDIG PLL Fractional Divide Register (PLLDIG_PLLFD) */
+#define PLLDIG_PLLFD(base) ((base) + 0x00000030)
+#define PLLDIG_PLLFD_MFN_SET(val) (PLLDIG_PLLFD_MFN_MASK & (val))
+#define PLLDIG_PLLFD_MFN_MASK (0x00007FFF)
+
+/* PLL Calibration Register 1 (PLLDIG_PLLCAL1) */
+#define PLLDIG_PLLCAL1(base) ((base) + 0x00000038)
+#define PLLDIG_PLLCAL1_NDAC1_SET(val) (PLLDIG_PLLCAL1_NDAC1_MASK & \
+ ((val) \
+ << PLLDIG_PLLCAL1_NDAC1_OFFSET))
+#define PLLDIG_PLLCAL1_NDAC1_OFFSET (24)
+#define PLLDIG_PLLCAL1_NDAC1_MASK (0x7F000000)
+
+/* Naming convention for PLL:
+ * ARMPLL - PLL0
+ * PERIPHPLL - PLL1
+ * ENETPLL - PLL2
+ * DDRPLL - PLL3
+ * VIDEOPLL - PLL4
+ */
+/* The min,max values for PLL VCO (Hz) */
+#define PERIPHPLL_MAX_VCO_RATE (1200000000)
+
+/* The min,max values for PLL PHI0 and PHI1 outputs (Hz) */
+#define PERIPHPLL_MAX_PHI0_MAX_RATE (400000000)
+#define PERIPHPLL_MAX_PHI1_MAX_RATE (100000000)
+
+/* The maximum value for PLL VCO according to data sheet */
+#define MAX_VCO_RATE (1300000000)
+#define MIN_VCO_RATE (650000000)
+
+enum s32v234_plldig_type {
+ S32_PLLDIG_ARM,
+ S32_PLLDIG_PERIPH,
+ S32_PLLDIG_ENET,
+ S32_PLLDIG_DDR,
+ S32_PLLDIG_VIDEO,
+};
+
+#endif
diff --git a/drivers/clk/s32/s32v234/src.h b/drivers/clk/s32/s32v234/src.h
new file mode 100644
index 000000000000..39fa973b7c3c
--- /dev/null
+++ b/drivers/clk/s32/s32v234/src.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ */
+#ifndef _SRC_H
+#define _SRC_H
+
+/* Source Reset Control: General Purpose Register 1 */
+#define SRC_GPR1 (src_base + 0x100)
+#define SRC_GPR1_ARMPLL_SRC_SEL_OFFSET (27)
+#define SRC_GPR1_ENETPLL_SRC_SEL_OFFSET (28)
+#define SRC_GPR1_DDRPLL_SRC_SEL_OFFSET (29)
+#define SRC_GPR1_PERIPHPLL_SRC_SEL_OFFSET (30)
+#define SRC_GPR1_VIDEOPLL_SRC_SEL_OFFSET (31)
+#define SRC_GPR1_XPLL_SRC_SEL_SIZE (1)
+
+#endif