summaryrefslogtreecommitdiffstats
path: root/drivers/interconnect/imx
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/interconnect/imx')
-rw-r--r--drivers/interconnect/imx/Kconfig21
-rw-r--r--drivers/interconnect/imx/Makefile11
-rw-r--r--drivers/interconnect/imx/imx.c337
-rw-r--r--drivers/interconnect/imx/imx.h108
-rw-r--r--drivers/interconnect/imx/imx8mm.c107
-rw-r--r--drivers/interconnect/imx/imx8mn.c96
-rw-r--r--drivers/interconnect/imx/imx8mp.c261
-rw-r--r--drivers/interconnect/imx/imx8mq.c107
8 files changed, 1048 insertions, 0 deletions
diff --git a/drivers/interconnect/imx/Kconfig b/drivers/interconnect/imx/Kconfig
new file mode 100644
index 000000000..c77255243
--- /dev/null
+++ b/drivers/interconnect/imx/Kconfig
@@ -0,0 +1,21 @@
+config INTERCONNECT_IMX
+ tristate "i.MX interconnect drivers"
+ depends on ARCH_MXC || COMPILE_TEST
+ help
+ Generic interconnect drivers for i.MX SOCs
+
+config INTERCONNECT_IMX8MM
+ tristate "i.MX8MM interconnect driver"
+ depends on INTERCONNECT_IMX
+
+config INTERCONNECT_IMX8MN
+ tristate "i.MX8MN interconnect driver"
+ depends on INTERCONNECT_IMX
+
+config INTERCONNECT_IMX8MQ
+ tristate "i.MX8MQ interconnect driver"
+ depends on INTERCONNECT_IMX
+
+config INTERCONNECT_IMX8MP
+ tristate "i.MX8MP interconnect driver"
+ depends on INTERCONNECT_IMX
diff --git a/drivers/interconnect/imx/Makefile b/drivers/interconnect/imx/Makefile
new file mode 100644
index 000000000..16d256cde
--- /dev/null
+++ b/drivers/interconnect/imx/Makefile
@@ -0,0 +1,11 @@
+imx-interconnect-objs := imx.o
+imx8mm-interconnect-objs := imx8mm.o
+imx8mq-interconnect-objs := imx8mq.o
+imx8mn-interconnect-objs := imx8mn.o
+imx8mp-interconnect-objs := imx8mp.o
+
+obj-$(CONFIG_INTERCONNECT_IMX) += imx-interconnect.o
+obj-$(CONFIG_INTERCONNECT_IMX8MM) += imx8mm-interconnect.o
+obj-$(CONFIG_INTERCONNECT_IMX8MQ) += imx8mq-interconnect.o
+obj-$(CONFIG_INTERCONNECT_IMX8MN) += imx8mn-interconnect.o
+obj-$(CONFIG_INTERCONNECT_IMX8MP) += imx8mp-interconnect.o
diff --git a/drivers/interconnect/imx/imx.c b/drivers/interconnect/imx/imx.c
new file mode 100644
index 000000000..979ed610f
--- /dev/null
+++ b/drivers/interconnect/imx/imx.c
@@ -0,0 +1,337 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Interconnect framework driver for i.MX SoC
+ *
+ * Copyright (c) 2019, BayLibre
+ * Copyright (c) 2019-2020, NXP
+ * Author: Alexandre Bailon <abailon@baylibre.com>
+ * Author: Leonard Crestez <leonard.crestez@nxp.com>
+ */
+
+#include <linux/device.h>
+#include <linux/interconnect-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+
+#include "imx.h"
+
+/* private icc_node data */
+struct imx_icc_node {
+ const struct imx_icc_node_desc *desc;
+ const struct imx_icc_noc_setting *setting;
+ struct device *qos_dev;
+ struct dev_pm_qos_request qos_req;
+ struct imx_icc_provider *imx_provider;
+};
+
+static int imx_icc_get_bw(struct icc_node *node, u32 *avg, u32 *peak)
+{
+ *avg = 0;
+ *peak = 0;
+
+ return 0;
+}
+
+static int imx_icc_node_set(struct icc_node *node)
+{
+ struct device *dev = node->provider->dev;
+ struct imx_icc_node *node_data = node->data;
+ void __iomem *base;
+ u32 prio;
+ u64 freq;
+
+ if (node_data->setting && node->peak_bw) {
+ base = node_data->setting->reg + node_data->imx_provider->noc_base;
+ if (node_data->setting->mode == IMX_NOC_MODE_FIXED) {
+ prio = node_data->setting->prio_level;
+ prio = PRIORITY_COMP_MARK | (prio << 8) | prio;
+ writel(prio, base + IMX_NOC_PRIO_REG);
+ writel(node_data->setting->mode, base + IMX_NOC_MODE_REG);
+ writel(node_data->setting->ext_control, base + IMX_NOC_EXT_CTL_REG);
+ dev_dbg(dev, "%s: mode: 0x%x, prio: 0x%x, ext_control: 0x%x\n",
+ node_data->desc->name, node_data->setting->mode, prio,
+ node_data->setting->ext_control);
+ } else if (node_data->setting->mode == IMX_NOC_MODE_UNCONFIGURED) {
+ dev_dbg(dev, "%s: mode not unconfigured\n", node_data->desc->name);
+ } else {
+ dev_info(dev, "%s: mode: %d not supported\n",
+ node_data->desc->name, node_data->setting->mode);
+ return -EOPNOTSUPP;
+ }
+ }
+
+ if (!node_data->qos_dev)
+ return 0;
+
+ freq = (node->avg_bw + node->peak_bw) * node_data->desc->adj->bw_mul;
+ do_div(freq, node_data->desc->adj->bw_div);
+ dev_dbg(dev, "node %s device %s avg_bw %ukBps peak_bw %ukBps min_freq %llukHz\n",
+ node->name, dev_name(node_data->qos_dev),
+ node->avg_bw, node->peak_bw, freq);
+
+ if (freq > S32_MAX) {
+ dev_err(dev, "%s can't request more than S32_MAX freq\n",
+ node->name);
+ return -ERANGE;
+ }
+
+ dev_pm_qos_update_request(&node_data->qos_req, freq);
+
+ return 0;
+}
+
+static int imx_icc_set(struct icc_node *src, struct icc_node *dst)
+{
+ int ret;
+
+ ret = imx_icc_node_set(src);
+ if (ret)
+ return ret;
+
+ return imx_icc_node_set(dst);
+}
+
+/* imx_icc_node_destroy() - Destroy an imx icc_node, including private data */
+static void imx_icc_node_destroy(struct icc_node *node)
+{
+ struct imx_icc_node *node_data = node->data;
+ int ret;
+
+ if (dev_pm_qos_request_active(&node_data->qos_req)) {
+ ret = dev_pm_qos_remove_request(&node_data->qos_req);
+ if (ret)
+ dev_warn(node->provider->dev,
+ "failed to remove qos request for %s\n",
+ dev_name(node_data->qos_dev));
+ }
+
+ put_device(node_data->qos_dev);
+ icc_node_del(node);
+ icc_node_destroy(node->id);
+}
+
+static int imx_icc_node_init_qos(struct icc_provider *provider,
+ struct icc_node *node)
+{
+ struct imx_icc_node *node_data = node->data;
+ const struct imx_icc_node_adj_desc *adj = node_data->desc->adj;
+ struct device *dev = provider->dev;
+ struct device_node *dn = NULL;
+ struct platform_device *pdev;
+
+ if (adj->main_noc) {
+ node_data->qos_dev = dev;
+ dev_dbg(dev, "icc node %s[%d] is main noc itself\n",
+ node->name, node->id);
+ } else {
+ dn = of_parse_phandle(dev->of_node, adj->phandle_name, 0);
+ if (!dn) {
+ dev_warn(dev, "Failed to parse %s\n",
+ adj->phandle_name);
+ return -ENODEV;
+ }
+ /* Allow scaling to be disabled on a per-node basis */
+ if (!of_device_is_available(dn)) {
+ dev_warn(dev, "Missing property %s, skip scaling %s\n",
+ adj->phandle_name, node->name);
+ of_node_put(dn);
+ return 0;
+ }
+
+ pdev = of_find_device_by_node(dn);
+ of_node_put(dn);
+ if (!pdev) {
+ dev_warn(dev, "node %s[%d] missing device for %pOF\n",
+ node->name, node->id, dn);
+ return -EPROBE_DEFER;
+ }
+ node_data->qos_dev = &pdev->dev;
+ dev_dbg(dev, "node %s[%d] has device node %pOF\n",
+ node->name, node->id, dn);
+ }
+
+ return dev_pm_qos_add_request(node_data->qos_dev,
+ &node_data->qos_req,
+ DEV_PM_QOS_MIN_FREQUENCY, 0);
+}
+
+static struct icc_node *imx_icc_node_add(struct imx_icc_provider *imx_provider,
+ const struct imx_icc_node_desc *node_desc,
+ const struct imx_icc_noc_setting *setting)
+{
+ struct icc_provider *provider = &imx_provider->provider;
+ struct device *dev = provider->dev;
+ struct imx_icc_node *node_data;
+ struct icc_node *node;
+ int ret;
+
+ node = icc_node_create(node_desc->id);
+ if (IS_ERR(node)) {
+ dev_err(dev, "failed to create node %d\n", node_desc->id);
+ return node;
+ }
+
+ if (node->data) {
+ dev_err(dev, "already created node %s id=%d\n",
+ node_desc->name, node_desc->id);
+ return ERR_PTR(-EEXIST);
+ }
+
+ node_data = devm_kzalloc(dev, sizeof(*node_data), GFP_KERNEL);
+ if (!node_data) {
+ icc_node_destroy(node->id);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ node->name = node_desc->name;
+ node->data = node_data;
+ node_data->desc = node_desc;
+ node_data->setting = setting;
+ node_data->imx_provider = imx_provider;
+ icc_node_add(node, provider);
+
+ if (node_desc->adj) {
+ ret = imx_icc_node_init_qos(provider, node);
+ if (ret < 0) {
+ imx_icc_node_destroy(node);
+ return ERR_PTR(ret);
+ }
+ }
+
+ return node;
+}
+
+static void imx_icc_unregister_nodes(struct icc_provider *provider)
+{
+ struct icc_node *node, *tmp;
+
+ list_for_each_entry_safe(node, tmp, &provider->nodes, node_list)
+ imx_icc_node_destroy(node);
+}
+
+static int imx_icc_register_nodes(struct imx_icc_provider *imx_provider,
+ const struct imx_icc_node_desc *descs,
+ int count,
+ const struct imx_icc_noc_setting *settings)
+{
+ struct icc_provider *provider = &imx_provider->provider;
+ struct icc_onecell_data *provider_data = provider->data;
+ int ret;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ struct icc_node *node;
+ const struct imx_icc_node_desc *node_desc = &descs[i];
+ size_t j;
+
+ node = imx_icc_node_add(imx_provider, node_desc,
+ settings ? &settings[node_desc->id] : NULL);
+ if (IS_ERR(node)) {
+ ret = dev_err_probe(provider->dev, PTR_ERR(node),
+ "failed to add %s\n", node_desc->name);
+ goto err;
+ }
+ provider_data->nodes[node->id] = node;
+
+ for (j = 0; j < node_desc->num_links; j++) {
+ ret = icc_link_create(node, node_desc->links[j]);
+ if (ret) {
+ dev_err(provider->dev, "failed to link node %d to %d: %d\n",
+ node->id, node_desc->links[j], ret);
+ goto err;
+ }
+ }
+ }
+
+ return 0;
+
+err:
+ imx_icc_unregister_nodes(provider);
+
+ return ret;
+}
+
+static int get_max_node_id(struct imx_icc_node_desc *nodes, int nodes_count)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < nodes_count; ++i)
+ if (nodes[i].id > ret)
+ ret = nodes[i].id;
+
+ return ret;
+}
+
+int imx_icc_register(struct platform_device *pdev,
+ struct imx_icc_node_desc *nodes, int nodes_count,
+ struct imx_icc_noc_setting *settings)
+{
+ struct device *dev = &pdev->dev;
+ struct icc_onecell_data *data;
+ struct imx_icc_provider *imx_provider;
+ struct icc_provider *provider;
+ int num_nodes;
+ int ret;
+
+ /* icc_onecell_data is indexed by node_id, unlike nodes param */
+ num_nodes = get_max_node_id(nodes, nodes_count) + 1;
+ data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ data->num_nodes = num_nodes;
+
+ imx_provider = devm_kzalloc(dev, sizeof(*imx_provider), GFP_KERNEL);
+ if (!imx_provider)
+ return -ENOMEM;
+ provider = &imx_provider->provider;
+ provider->set = imx_icc_set;
+ provider->get_bw = imx_icc_get_bw;
+ provider->aggregate = icc_std_aggregate;
+ provider->xlate = of_icc_xlate_onecell;
+ provider->data = data;
+ provider->dev = dev->parent;
+
+ icc_provider_init(provider);
+
+ platform_set_drvdata(pdev, imx_provider);
+
+ if (settings) {
+ imx_provider->noc_base = devm_of_iomap(dev, provider->dev->of_node, 0, NULL);
+ if (IS_ERR(imx_provider->noc_base)) {
+ ret = PTR_ERR(imx_provider->noc_base);
+ dev_err(dev, "Error mapping NoC: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = imx_icc_register_nodes(imx_provider, nodes, nodes_count, settings);
+ if (ret)
+ return ret;
+
+ ret = icc_provider_register(provider);
+ if (ret)
+ goto err_unregister_nodes;
+
+ return 0;
+
+err_unregister_nodes:
+ imx_icc_unregister_nodes(&imx_provider->provider);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(imx_icc_register);
+
+void imx_icc_unregister(struct platform_device *pdev)
+{
+ struct imx_icc_provider *imx_provider = platform_get_drvdata(pdev);
+
+ icc_provider_deregister(&imx_provider->provider);
+ imx_icc_unregister_nodes(&imx_provider->provider);
+}
+EXPORT_SYMBOL_GPL(imx_icc_unregister);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/interconnect/imx/imx.h b/drivers/interconnect/imx/imx.h
new file mode 100644
index 000000000..895907cdc
--- /dev/null
+++ b/drivers/interconnect/imx/imx.h
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Interconnect framework driver for i.MX SoC
+ *
+ * Copyright (c) 2019, BayLibre
+ * Copyright (c) 2019-2020, NXP
+ * Author: Alexandre Bailon <abailon@baylibre.com>
+ * Author: Leonard Crestez <leonard.crestez@nxp.com>
+ */
+#ifndef __DRIVERS_INTERCONNECT_IMX_H
+#define __DRIVERS_INTERCONNECT_IMX_H
+
+#include <linux/interconnect-provider.h>
+#include <linux/kernel.h>
+
+#define IMX_ICC_MAX_LINKS 4
+
+/*
+ * High throughput priority level in Regulator mode
+ * Read Priority in Fixed/Limiter mode
+ */
+#define PRIORITY0_SHIFT 0
+/*
+ * Low throughput priority level in Regulator mode
+ * Write Priority in Fixed/Limiter mode
+ */
+#define PRIORITY1_SHIFT 8
+#define PRIORITY_MASK 0x7
+
+#define PRIORITY_COMP_MARK BIT(31) /* Must set */
+
+#define IMX_NOC_MODE_FIXED 0
+#define IMX_NOC_MODE_LIMITER 1
+#define IMX_NOC_MODE_BYPASS 2
+#define IMX_NOC_MODE_REGULATOR 3
+#define IMX_NOC_MODE_UNCONFIGURED 0xFF
+
+#define IMX_NOC_PRIO_REG 0x8
+#define IMX_NOC_MODE_REG 0xC
+#define IMX_NOC_BANDWIDTH_REG 0x10
+#define IMX_NOC_SATURATION 0x14
+#define IMX_NOC_EXT_CTL_REG 0x18
+
+struct imx_icc_provider {
+ void __iomem *noc_base;
+ struct icc_provider provider;
+};
+
+/*
+ * struct imx_icc_node_adj - Describe a dynamic adjustable node
+ */
+struct imx_icc_node_adj_desc {
+ unsigned int bw_mul, bw_div;
+ const char *phandle_name;
+ bool main_noc;
+};
+
+/*
+ * struct imx_icc_node - Describe an interconnect node
+ * @name: name of the node
+ * @id: an unique id to identify the node
+ * @links: an array of slaves' node id
+ * @num_links: number of id defined in links
+ */
+struct imx_icc_node_desc {
+ const char *name;
+ u16 id;
+ u16 links[IMX_ICC_MAX_LINKS];
+ u16 num_links;
+ const struct imx_icc_node_adj_desc *adj;
+};
+
+/*
+ * struct imx_icc_noc_setting - Describe an interconnect node setting
+ * @reg: register offset inside the NoC
+ * @prio_level: priority level
+ * @mode: functional mode
+ * @ext_control: external input control
+ */
+struct imx_icc_noc_setting {
+ u32 reg;
+ u32 prio_level;
+ u32 mode;
+ u32 ext_control;
+};
+
+#define DEFINE_BUS_INTERCONNECT(_name, _id, _adj, ...) \
+ { \
+ .id = _id, \
+ .name = _name, \
+ .adj = _adj, \
+ .num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })), \
+ .links = { __VA_ARGS__ }, \
+ }
+
+#define DEFINE_BUS_MASTER(_name, _id, _dest_id) \
+ DEFINE_BUS_INTERCONNECT(_name, _id, NULL, _dest_id)
+
+#define DEFINE_BUS_SLAVE(_name, _id, _adj) \
+ DEFINE_BUS_INTERCONNECT(_name, _id, _adj)
+
+int imx_icc_register(struct platform_device *pdev,
+ struct imx_icc_node_desc *nodes,
+ int nodes_count,
+ struct imx_icc_noc_setting *noc_settings);
+void imx_icc_unregister(struct platform_device *pdev);
+
+#endif /* __DRIVERS_INTERCONNECT_IMX_H */
diff --git a/drivers/interconnect/imx/imx8mm.c b/drivers/interconnect/imx/imx8mm.c
new file mode 100644
index 000000000..b43325364
--- /dev/null
+++ b/drivers/interconnect/imx/imx8mm.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Interconnect framework driver for i.MX8MM SoC
+ *
+ * Copyright (c) 2019, BayLibre
+ * Copyright (c) 2019-2020, NXP
+ * Author: Alexandre Bailon <abailon@baylibre.com>
+ * Author: Leonard Crestez <leonard.crestez@nxp.com>
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <dt-bindings/interconnect/imx8mm.h>
+
+#include "imx.h"
+
+static const struct imx_icc_node_adj_desc imx8mm_dram_adj = {
+ .bw_mul = 1,
+ .bw_div = 16,
+ .phandle_name = "fsl,ddrc",
+};
+
+static const struct imx_icc_node_adj_desc imx8mm_noc_adj = {
+ .bw_mul = 1,
+ .bw_div = 16,
+ .main_noc = true,
+};
+
+/*
+ * Describe bus masters, slaves and connections between them
+ *
+ * This is a simplified subset of the bus diagram, there are several other
+ * PL301 nics which are skipped/merged into PL301_MAIN
+ */
+static struct imx_icc_node_desc nodes[] = {
+ DEFINE_BUS_INTERCONNECT("NOC", IMX8MM_ICN_NOC, &imx8mm_noc_adj,
+ IMX8MM_ICS_DRAM, IMX8MM_ICN_MAIN),
+
+ DEFINE_BUS_SLAVE("DRAM", IMX8MM_ICS_DRAM, &imx8mm_dram_adj),
+ DEFINE_BUS_SLAVE("OCRAM", IMX8MM_ICS_OCRAM, NULL),
+ DEFINE_BUS_MASTER("A53", IMX8MM_ICM_A53, IMX8MM_ICN_NOC),
+
+ /* VPUMIX */
+ DEFINE_BUS_MASTER("VPU H1", IMX8MM_ICM_VPU_H1, IMX8MM_ICN_VIDEO),
+ DEFINE_BUS_MASTER("VPU G1", IMX8MM_ICM_VPU_G1, IMX8MM_ICN_VIDEO),
+ DEFINE_BUS_MASTER("VPU G2", IMX8MM_ICM_VPU_G2, IMX8MM_ICN_VIDEO),
+ DEFINE_BUS_INTERCONNECT("PL301_VIDEO", IMX8MM_ICN_VIDEO, NULL, IMX8MM_ICN_NOC),
+
+ /* GPUMIX */
+ DEFINE_BUS_MASTER("GPU 2D", IMX8MM_ICM_GPU2D, IMX8MM_ICN_GPU),
+ DEFINE_BUS_MASTER("GPU 3D", IMX8MM_ICM_GPU3D, IMX8MM_ICN_GPU),
+ DEFINE_BUS_INTERCONNECT("PL301_GPU", IMX8MM_ICN_GPU, NULL, IMX8MM_ICN_NOC),
+
+ /* DISPLAYMIX */
+ DEFINE_BUS_MASTER("CSI", IMX8MM_ICM_CSI, IMX8MM_ICN_MIPI),
+ DEFINE_BUS_MASTER("LCDIF", IMX8MM_ICM_LCDIF, IMX8MM_ICN_MIPI),
+ DEFINE_BUS_INTERCONNECT("PL301_MIPI", IMX8MM_ICN_MIPI, NULL, IMX8MM_ICN_NOC),
+
+ /* HSIO */
+ DEFINE_BUS_MASTER("USB1", IMX8MM_ICM_USB1, IMX8MM_ICN_HSIO),
+ DEFINE_BUS_MASTER("USB2", IMX8MM_ICM_USB2, IMX8MM_ICN_HSIO),
+ DEFINE_BUS_MASTER("PCIE", IMX8MM_ICM_PCIE, IMX8MM_ICN_HSIO),
+ DEFINE_BUS_INTERCONNECT("PL301_HSIO", IMX8MM_ICN_HSIO, NULL, IMX8MM_ICN_NOC),
+
+ /* Audio */
+ DEFINE_BUS_MASTER("SDMA2", IMX8MM_ICM_SDMA2, IMX8MM_ICN_AUDIO),
+ DEFINE_BUS_MASTER("SDMA3", IMX8MM_ICM_SDMA3, IMX8MM_ICN_AUDIO),
+ DEFINE_BUS_INTERCONNECT("PL301_AUDIO", IMX8MM_ICN_AUDIO, NULL, IMX8MM_ICN_MAIN),
+
+ /* Ethernet */
+ DEFINE_BUS_MASTER("ENET", IMX8MM_ICM_ENET, IMX8MM_ICN_ENET),
+ DEFINE_BUS_INTERCONNECT("PL301_ENET", IMX8MM_ICN_ENET, NULL, IMX8MM_ICN_MAIN),
+
+ /* Other */
+ DEFINE_BUS_MASTER("SDMA1", IMX8MM_ICM_SDMA1, IMX8MM_ICN_MAIN),
+ DEFINE_BUS_MASTER("NAND", IMX8MM_ICM_NAND, IMX8MM_ICN_MAIN),
+ DEFINE_BUS_MASTER("USDHC1", IMX8MM_ICM_USDHC1, IMX8MM_ICN_MAIN),
+ DEFINE_BUS_MASTER("USDHC2", IMX8MM_ICM_USDHC2, IMX8MM_ICN_MAIN),
+ DEFINE_BUS_MASTER("USDHC3", IMX8MM_ICM_USDHC3, IMX8MM_ICN_MAIN),
+ DEFINE_BUS_INTERCONNECT("PL301_MAIN", IMX8MM_ICN_MAIN, NULL,
+ IMX8MM_ICN_NOC, IMX8MM_ICS_OCRAM),
+};
+
+static int imx8mm_icc_probe(struct platform_device *pdev)
+{
+ return imx_icc_register(pdev, nodes, ARRAY_SIZE(nodes), NULL);
+}
+
+static int imx8mm_icc_remove(struct platform_device *pdev)
+{
+ imx_icc_unregister(pdev);
+
+ return 0;
+}
+
+static struct platform_driver imx8mm_icc_driver = {
+ .probe = imx8mm_icc_probe,
+ .remove = imx8mm_icc_remove,
+ .driver = {
+ .name = "imx8mm-interconnect",
+ },
+};
+
+module_platform_driver(imx8mm_icc_driver);
+MODULE_AUTHOR("Alexandre Bailon <abailon@baylibre.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx8mm-interconnect");
diff --git a/drivers/interconnect/imx/imx8mn.c b/drivers/interconnect/imx/imx8mn.c
new file mode 100644
index 000000000..8ce6d8e4b
--- /dev/null
+++ b/drivers/interconnect/imx/imx8mn.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Interconnect framework driver for i.MX8MN SoC
+ *
+ * Copyright (c) 2019-2020, NXP
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <dt-bindings/interconnect/imx8mn.h>
+
+#include "imx.h"
+
+static const struct imx_icc_node_adj_desc imx8mn_dram_adj = {
+ .bw_mul = 1,
+ .bw_div = 4,
+ .phandle_name = "fsl,ddrc",
+};
+
+static const struct imx_icc_node_adj_desc imx8mn_noc_adj = {
+ .bw_mul = 1,
+ .bw_div = 4,
+ .main_noc = true,
+};
+
+/*
+ * Describe bus masters, slaves and connections between them
+ *
+ * This is a simplified subset of the bus diagram, there are several other
+ * PL301 nics which are skipped/merged into PL301_MAIN
+ */
+static struct imx_icc_node_desc nodes[] = {
+ DEFINE_BUS_INTERCONNECT("NOC", IMX8MN_ICN_NOC, &imx8mn_noc_adj,
+ IMX8MN_ICS_DRAM, IMX8MN_ICN_MAIN),
+
+ DEFINE_BUS_SLAVE("DRAM", IMX8MN_ICS_DRAM, &imx8mn_dram_adj),
+ DEFINE_BUS_SLAVE("OCRAM", IMX8MN_ICS_OCRAM, NULL),
+ DEFINE_BUS_MASTER("A53", IMX8MN_ICM_A53, IMX8MN_ICN_NOC),
+
+ /* GPUMIX */
+ DEFINE_BUS_MASTER("GPU", IMX8MN_ICM_GPU, IMX8MN_ICN_GPU),
+ DEFINE_BUS_INTERCONNECT("PL301_GPU", IMX8MN_ICN_GPU, NULL, IMX8MN_ICN_NOC),
+
+ /* DISPLAYMIX */
+ DEFINE_BUS_MASTER("CSI1", IMX8MN_ICM_CSI1, IMX8MN_ICN_MIPI),
+ DEFINE_BUS_MASTER("CSI2", IMX8MN_ICM_CSI2, IMX8MN_ICN_MIPI),
+ DEFINE_BUS_MASTER("ISI", IMX8MN_ICM_ISI, IMX8MN_ICN_MIPI),
+ DEFINE_BUS_MASTER("LCDIF", IMX8MN_ICM_LCDIF, IMX8MN_ICN_MIPI),
+ DEFINE_BUS_INTERCONNECT("PL301_MIPI", IMX8MN_ICN_MIPI, NULL, IMX8MN_ICN_NOC),
+
+ /* USB goes straight to NOC */
+ DEFINE_BUS_MASTER("USB", IMX8MN_ICM_USB, IMX8MN_ICN_NOC),
+
+ /* Audio */
+ DEFINE_BUS_MASTER("SDMA2", IMX8MN_ICM_SDMA2, IMX8MN_ICN_AUDIO),
+ DEFINE_BUS_MASTER("SDMA3", IMX8MN_ICM_SDMA3, IMX8MN_ICN_AUDIO),
+ DEFINE_BUS_INTERCONNECT("PL301_AUDIO", IMX8MN_ICN_AUDIO, NULL, IMX8MN_ICN_MAIN),
+
+ /* Ethernet */
+ DEFINE_BUS_MASTER("ENET", IMX8MN_ICM_ENET, IMX8MN_ICN_ENET),
+ DEFINE_BUS_INTERCONNECT("PL301_ENET", IMX8MN_ICN_ENET, NULL, IMX8MN_ICN_MAIN),
+
+ /* Other */
+ DEFINE_BUS_MASTER("SDMA1", IMX8MN_ICM_SDMA1, IMX8MN_ICN_MAIN),
+ DEFINE_BUS_MASTER("NAND", IMX8MN_ICM_NAND, IMX8MN_ICN_MAIN),
+ DEFINE_BUS_MASTER("USDHC1", IMX8MN_ICM_USDHC1, IMX8MN_ICN_MAIN),
+ DEFINE_BUS_MASTER("USDHC2", IMX8MN_ICM_USDHC2, IMX8MN_ICN_MAIN),
+ DEFINE_BUS_MASTER("USDHC3", IMX8MN_ICM_USDHC3, IMX8MN_ICN_MAIN),
+ DEFINE_BUS_INTERCONNECT("PL301_MAIN", IMX8MN_ICN_MAIN, NULL,
+ IMX8MN_ICN_NOC, IMX8MN_ICS_OCRAM),
+};
+
+static int imx8mn_icc_probe(struct platform_device *pdev)
+{
+ return imx_icc_register(pdev, nodes, ARRAY_SIZE(nodes), NULL);
+}
+
+static int imx8mn_icc_remove(struct platform_device *pdev)
+{
+ imx_icc_unregister(pdev);
+
+ return 0;
+}
+
+static struct platform_driver imx8mn_icc_driver = {
+ .probe = imx8mn_icc_probe,
+ .remove = imx8mn_icc_remove,
+ .driver = {
+ .name = "imx8mn-interconnect",
+ },
+};
+
+module_platform_driver(imx8mn_icc_driver);
+MODULE_ALIAS("platform:imx8mn-interconnect");
+MODULE_AUTHOR("Leonard Crestez <leonard.crestez@nxp.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/interconnect/imx/imx8mp.c b/drivers/interconnect/imx/imx8mp.c
new file mode 100644
index 000000000..8bfaf173f
--- /dev/null
+++ b/drivers/interconnect/imx/imx8mp.c
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Interconnect framework driver for i.MX8MP SoC
+ *
+ * Copyright 2022 NXP
+ * Peng Fan <peng.fan@nxp.com>
+ */
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <dt-bindings/interconnect/fsl,imx8mp.h>
+
+#include "imx.h"
+
+static const struct imx_icc_node_adj_desc imx8mp_noc_adj = {
+ .bw_mul = 1,
+ .bw_div = 16,
+ .main_noc = true,
+};
+
+static struct imx_icc_noc_setting noc_setting_nodes[] = {
+ [IMX8MP_ICM_MLMIX] = {
+ .reg = 0x180,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 3,
+ },
+ [IMX8MP_ICM_DSP] = {
+ .reg = 0x200,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 3,
+ },
+ [IMX8MP_ICM_SDMA2PER] = {
+ .reg = 0x280,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 4,
+ },
+ [IMX8MP_ICM_SDMA2BURST] = {
+ .reg = 0x300,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 4,
+ },
+ [IMX8MP_ICM_SDMA3PER] = {
+ .reg = 0x380,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 4,
+ },
+ [IMX8MP_ICM_SDMA3BURST] = {
+ .reg = 0x400,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 4,
+ },
+ [IMX8MP_ICM_EDMA] = {
+ .reg = 0x480,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 4,
+ },
+ [IMX8MP_ICM_GPU3D] = {
+ .reg = 0x500,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 3,
+ },
+ [IMX8MP_ICM_GPU2D] = {
+ .reg = 0x580,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 3,
+ },
+ [IMX8MP_ICM_HRV] = {
+ .reg = 0x600,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 2,
+ .ext_control = 1,
+ },
+ [IMX8MP_ICM_LCDIF_HDMI] = {
+ .reg = 0x680,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 2,
+ .ext_control = 1,
+ },
+ [IMX8MP_ICM_HDCP] = {
+ .reg = 0x700,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 5,
+ },
+ [IMX8MP_ICM_NOC_PCIE] = {
+ .reg = 0x780,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 3,
+ },
+ [IMX8MP_ICM_USB1] = {
+ .reg = 0x800,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 3,
+ },
+ [IMX8MP_ICM_USB2] = {
+ .reg = 0x880,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 3,
+ },
+ [IMX8MP_ICM_PCIE] = {
+ .reg = 0x900,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 3,
+ },
+ [IMX8MP_ICM_LCDIF_RD] = {
+ .reg = 0x980,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 2,
+ .ext_control = 1,
+ },
+ [IMX8MP_ICM_LCDIF_WR] = {
+ .reg = 0xa00,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 2,
+ .ext_control = 1,
+ },
+ [IMX8MP_ICM_ISI0] = {
+ .reg = 0xa80,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 2,
+ .ext_control = 1,
+ },
+ [IMX8MP_ICM_ISI1] = {
+ .reg = 0xb00,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 2,
+ .ext_control = 1,
+ },
+ [IMX8MP_ICM_ISI2] = {
+ .reg = 0xb80,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 2,
+ .ext_control = 1,
+ },
+ [IMX8MP_ICM_ISP0] = {
+ .reg = 0xc00,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 7,
+ },
+ [IMX8MP_ICM_ISP1] = {
+ .reg = 0xc80,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 7,
+ },
+ [IMX8MP_ICM_DWE] = {
+ .reg = 0xd00,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 7,
+ },
+ [IMX8MP_ICM_VPU_G1] = {
+ .reg = 0xd80,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 3,
+ },
+ [IMX8MP_ICM_VPU_G2] = {
+ .reg = 0xe00,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 3,
+ },
+ [IMX8MP_ICM_VPU_H1] = {
+ .reg = 0xe80,
+ .mode = IMX_NOC_MODE_FIXED,
+ .prio_level = 3,
+ },
+ [IMX8MP_ICN_MEDIA] = {
+ .mode = IMX_NOC_MODE_UNCONFIGURED,
+ },
+ [IMX8MP_ICN_VIDEO] = {
+ .mode = IMX_NOC_MODE_UNCONFIGURED,
+ },
+ [IMX8MP_ICN_AUDIO] = {
+ .mode = IMX_NOC_MODE_UNCONFIGURED,
+ },
+ [IMX8MP_ICN_HDMI] = {
+ .mode = IMX_NOC_MODE_UNCONFIGURED,
+ },
+ [IMX8MP_ICN_GPU] = {
+ .mode = IMX_NOC_MODE_UNCONFIGURED,
+ },
+ [IMX8MP_ICN_HSIO] = {
+ .mode = IMX_NOC_MODE_UNCONFIGURED,
+ },
+};
+
+/* Describe bus masters, slaves and connections between them */
+static struct imx_icc_node_desc nodes[] = {
+ DEFINE_BUS_INTERCONNECT("NOC", IMX8MP_ICN_NOC, &imx8mp_noc_adj,
+ IMX8MP_ICS_DRAM, IMX8MP_ICN_MAIN),
+
+ DEFINE_BUS_SLAVE("OCRAM", IMX8MP_ICS_OCRAM, NULL),
+ DEFINE_BUS_SLAVE("DRAM", IMX8MP_ICS_DRAM, NULL),
+ DEFINE_BUS_MASTER("A53", IMX8MP_ICM_A53, IMX8MP_ICN_NOC),
+ DEFINE_BUS_MASTER("SUPERMIX", IMX8MP_ICM_SUPERMIX, IMX8MP_ICN_NOC),
+ DEFINE_BUS_MASTER("GIC", IMX8MP_ICM_GIC, IMX8MP_ICN_NOC),
+ DEFINE_BUS_MASTER("MLMIX", IMX8MP_ICM_MLMIX, IMX8MP_ICN_NOC),
+
+ DEFINE_BUS_INTERCONNECT("NOC_AUDIO", IMX8MP_ICN_AUDIO, NULL, IMX8MP_ICN_NOC),
+ DEFINE_BUS_MASTER("DSP", IMX8MP_ICM_DSP, IMX8MP_ICN_AUDIO),
+ DEFINE_BUS_MASTER("SDMA2PER", IMX8MP_ICM_SDMA2PER, IMX8MP_ICN_AUDIO),
+ DEFINE_BUS_MASTER("SDMA2BURST", IMX8MP_ICM_SDMA2BURST, IMX8MP_ICN_AUDIO),
+ DEFINE_BUS_MASTER("SDMA3PER", IMX8MP_ICM_SDMA3PER, IMX8MP_ICN_AUDIO),
+ DEFINE_BUS_MASTER("SDMA3BURST", IMX8MP_ICM_SDMA3BURST, IMX8MP_ICN_AUDIO),
+ DEFINE_BUS_MASTER("EDMA", IMX8MP_ICM_EDMA, IMX8MP_ICN_AUDIO),
+
+ DEFINE_BUS_INTERCONNECT("NOC_GPU", IMX8MP_ICN_GPU, NULL, IMX8MP_ICN_NOC),
+ DEFINE_BUS_MASTER("GPU 2D", IMX8MP_ICM_GPU2D, IMX8MP_ICN_GPU),
+ DEFINE_BUS_MASTER("GPU 3D", IMX8MP_ICM_GPU3D, IMX8MP_ICN_GPU),
+
+ DEFINE_BUS_INTERCONNECT("NOC_HDMI", IMX8MP_ICN_HDMI, NULL, IMX8MP_ICN_NOC),
+ DEFINE_BUS_MASTER("HRV", IMX8MP_ICM_HRV, IMX8MP_ICN_HDMI),
+ DEFINE_BUS_MASTER("LCDIF_HDMI", IMX8MP_ICM_LCDIF_HDMI, IMX8MP_ICN_HDMI),
+ DEFINE_BUS_MASTER("HDCP", IMX8MP_ICM_HDCP, IMX8MP_ICN_HDMI),
+
+ DEFINE_BUS_INTERCONNECT("NOC_HSIO", IMX8MP_ICN_HSIO, NULL, IMX8MP_ICN_NOC),
+ DEFINE_BUS_MASTER("NOC_PCIE", IMX8MP_ICM_NOC_PCIE, IMX8MP_ICN_HSIO),
+ DEFINE_BUS_MASTER("USB1", IMX8MP_ICM_USB1, IMX8MP_ICN_HSIO),
+ DEFINE_BUS_MASTER("USB2", IMX8MP_ICM_USB2, IMX8MP_ICN_HSIO),
+ DEFINE_BUS_MASTER("PCIE", IMX8MP_ICM_PCIE, IMX8MP_ICN_HSIO),
+
+ DEFINE_BUS_INTERCONNECT("NOC_MEDIA", IMX8MP_ICN_MEDIA, NULL, IMX8MP_ICN_NOC),
+ DEFINE_BUS_MASTER("LCDIF_RD", IMX8MP_ICM_LCDIF_RD, IMX8MP_ICN_MEDIA),
+ DEFINE_BUS_MASTER("LCDIF_WR", IMX8MP_ICM_LCDIF_WR, IMX8MP_ICN_MEDIA),
+ DEFINE_BUS_MASTER("ISI0", IMX8MP_ICM_ISI0, IMX8MP_ICN_MEDIA),
+ DEFINE_BUS_MASTER("ISI1", IMX8MP_ICM_ISI1, IMX8MP_ICN_MEDIA),
+ DEFINE_BUS_MASTER("ISI2", IMX8MP_ICM_ISI2, IMX8MP_ICN_MEDIA),
+ DEFINE_BUS_MASTER("ISP0", IMX8MP_ICM_ISP0, IMX8MP_ICN_MEDIA),
+ DEFINE_BUS_MASTER("ISP1", IMX8MP_ICM_ISP1, IMX8MP_ICN_MEDIA),
+ DEFINE_BUS_MASTER("DWE", IMX8MP_ICM_DWE, IMX8MP_ICN_MEDIA),
+
+ DEFINE_BUS_INTERCONNECT("NOC_VIDEO", IMX8MP_ICN_VIDEO, NULL, IMX8MP_ICN_NOC),
+ DEFINE_BUS_MASTER("VPU G1", IMX8MP_ICM_VPU_G1, IMX8MP_ICN_VIDEO),
+ DEFINE_BUS_MASTER("VPU G2", IMX8MP_ICM_VPU_G2, IMX8MP_ICN_VIDEO),
+ DEFINE_BUS_MASTER("VPU H1", IMX8MP_ICM_VPU_H1, IMX8MP_ICN_VIDEO),
+ DEFINE_BUS_INTERCONNECT("PL301_MAIN", IMX8MP_ICN_MAIN, NULL,
+ IMX8MP_ICN_NOC, IMX8MP_ICS_OCRAM),
+};
+
+static int imx8mp_icc_probe(struct platform_device *pdev)
+{
+ return imx_icc_register(pdev, nodes, ARRAY_SIZE(nodes), noc_setting_nodes);
+}
+
+static int imx8mp_icc_remove(struct platform_device *pdev)
+{
+ imx_icc_unregister(pdev);
+
+ return 0;
+}
+
+static struct platform_driver imx8mp_icc_driver = {
+ .probe = imx8mp_icc_probe,
+ .remove = imx8mp_icc_remove,
+ .driver = {
+ .name = "imx8mp-interconnect",
+ },
+};
+
+module_platform_driver(imx8mp_icc_driver);
+MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx8mp-interconnect");
diff --git a/drivers/interconnect/imx/imx8mq.c b/drivers/interconnect/imx/imx8mq.c
new file mode 100644
index 000000000..b6fb71305
--- /dev/null
+++ b/drivers/interconnect/imx/imx8mq.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Interconnect framework driver for i.MX8MQ SoC
+ *
+ * Copyright (c) 2019-2020, NXP
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interconnect-provider.h>
+#include <dt-bindings/interconnect/imx8mq.h>
+
+#include "imx.h"
+
+static const struct imx_icc_node_adj_desc imx8mq_dram_adj = {
+ .bw_mul = 1,
+ .bw_div = 4,
+ .phandle_name = "fsl,ddrc",
+};
+
+static const struct imx_icc_node_adj_desc imx8mq_noc_adj = {
+ .bw_mul = 1,
+ .bw_div = 4,
+ .main_noc = true,
+};
+
+/*
+ * Describe bus masters, slaves and connections between them
+ *
+ * This is a simplified subset of the bus diagram, there are several other
+ * PL301 nics which are skipped/merged into PL301_MAIN
+ */
+static struct imx_icc_node_desc nodes[] = {
+ DEFINE_BUS_INTERCONNECT("NOC", IMX8MQ_ICN_NOC, &imx8mq_noc_adj,
+ IMX8MQ_ICS_DRAM, IMX8MQ_ICN_MAIN),
+
+ DEFINE_BUS_SLAVE("DRAM", IMX8MQ_ICS_DRAM, &imx8mq_dram_adj),
+ DEFINE_BUS_SLAVE("OCRAM", IMX8MQ_ICS_OCRAM, NULL),
+ DEFINE_BUS_MASTER("A53", IMX8MQ_ICM_A53, IMX8MQ_ICN_NOC),
+
+ /* VPUMIX */
+ DEFINE_BUS_MASTER("VPU", IMX8MQ_ICM_VPU, IMX8MQ_ICN_VIDEO),
+ DEFINE_BUS_INTERCONNECT("PL301_VIDEO", IMX8MQ_ICN_VIDEO, NULL, IMX8MQ_ICN_NOC),
+
+ /* GPUMIX */
+ DEFINE_BUS_MASTER("GPU", IMX8MQ_ICM_GPU, IMX8MQ_ICN_GPU),
+ DEFINE_BUS_INTERCONNECT("PL301_GPU", IMX8MQ_ICN_GPU, NULL, IMX8MQ_ICN_NOC),
+
+ /* DISPMIX (only for DCSS) */
+ DEFINE_BUS_MASTER("DC", IMX8MQ_ICM_DCSS, IMX8MQ_ICN_DCSS),
+ DEFINE_BUS_INTERCONNECT("PL301_DC", IMX8MQ_ICN_DCSS, NULL, IMX8MQ_ICN_NOC),
+
+ /* USBMIX */
+ DEFINE_BUS_MASTER("USB1", IMX8MQ_ICM_USB1, IMX8MQ_ICN_USB),
+ DEFINE_BUS_MASTER("USB2", IMX8MQ_ICM_USB2, IMX8MQ_ICN_USB),
+ DEFINE_BUS_INTERCONNECT("PL301_USB", IMX8MQ_ICN_USB, NULL, IMX8MQ_ICN_NOC),
+
+ /* PL301_DISPLAY (IPs other than DCSS, inside SUPERMIX) */
+ DEFINE_BUS_MASTER("CSI1", IMX8MQ_ICM_CSI1, IMX8MQ_ICN_DISPLAY),
+ DEFINE_BUS_MASTER("CSI2", IMX8MQ_ICM_CSI2, IMX8MQ_ICN_DISPLAY),
+ DEFINE_BUS_MASTER("LCDIF", IMX8MQ_ICM_LCDIF, IMX8MQ_ICN_DISPLAY),
+ DEFINE_BUS_INTERCONNECT("PL301_DISPLAY", IMX8MQ_ICN_DISPLAY, NULL, IMX8MQ_ICN_MAIN),
+
+ /* AUDIO */
+ DEFINE_BUS_MASTER("SDMA2", IMX8MQ_ICM_SDMA2, IMX8MQ_ICN_AUDIO),
+ DEFINE_BUS_INTERCONNECT("PL301_AUDIO", IMX8MQ_ICN_AUDIO, NULL, IMX8MQ_ICN_DISPLAY),
+
+ /* ENET */
+ DEFINE_BUS_MASTER("ENET", IMX8MQ_ICM_ENET, IMX8MQ_ICN_ENET),
+ DEFINE_BUS_INTERCONNECT("PL301_ENET", IMX8MQ_ICN_ENET, NULL, IMX8MQ_ICN_MAIN),
+
+ /* OTHER */
+ DEFINE_BUS_MASTER("SDMA1", IMX8MQ_ICM_SDMA1, IMX8MQ_ICN_MAIN),
+ DEFINE_BUS_MASTER("NAND", IMX8MQ_ICM_NAND, IMX8MQ_ICN_MAIN),
+ DEFINE_BUS_MASTER("USDHC1", IMX8MQ_ICM_USDHC1, IMX8MQ_ICN_MAIN),
+ DEFINE_BUS_MASTER("USDHC2", IMX8MQ_ICM_USDHC2, IMX8MQ_ICN_MAIN),
+ DEFINE_BUS_MASTER("PCIE1", IMX8MQ_ICM_PCIE1, IMX8MQ_ICN_MAIN),
+ DEFINE_BUS_MASTER("PCIE2", IMX8MQ_ICM_PCIE2, IMX8MQ_ICN_MAIN),
+ DEFINE_BUS_INTERCONNECT("PL301_MAIN", IMX8MQ_ICN_MAIN, NULL,
+ IMX8MQ_ICN_NOC, IMX8MQ_ICS_OCRAM),
+};
+
+static int imx8mq_icc_probe(struct platform_device *pdev)
+{
+ return imx_icc_register(pdev, nodes, ARRAY_SIZE(nodes), NULL);
+}
+
+static int imx8mq_icc_remove(struct platform_device *pdev)
+{
+ imx_icc_unregister(pdev);
+
+ return 0;
+}
+
+static struct platform_driver imx8mq_icc_driver = {
+ .probe = imx8mq_icc_probe,
+ .remove = imx8mq_icc_remove,
+ .driver = {
+ .name = "imx8mq-interconnect",
+ .sync_state = icc_sync_state,
+ },
+};
+
+module_platform_driver(imx8mq_icc_driver);
+MODULE_ALIAS("platform:imx8mq-interconnect");
+MODULE_AUTHOR("Leonard Crestez <leonard.crestez@nxp.com>");
+MODULE_LICENSE("GPL v2");