Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -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
@@ -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
+338
View File
@@ -0,0 +1,338 @@
// 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_DESCRIPTION("Interconnect framework driver for i.MX SoC");
MODULE_LICENSE("GPL v2");
+113
View File
@@ -0,0 +1,113 @@
/* 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/args.h>
#include <linux/bits.h>
#include <linux/types.h>
#include <linux/interconnect-provider.h>
struct platform_device;
#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 = COUNT_ARGS(__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 */
@@ -0,0 +1,101 @@
// 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 struct platform_driver imx8mm_icc_driver = {
.probe = imx8mm_icc_probe,
.remove = imx_icc_unregister,
.driver = {
.name = "imx8mm-interconnect",
},
};
module_platform_driver(imx8mm_icc_driver);
MODULE_AUTHOR("Alexandre Bailon <abailon@baylibre.com>");
MODULE_DESCRIPTION("Interconnect framework driver for i.MX8MM SoC");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:imx8mm-interconnect");
@@ -0,0 +1,90 @@
// 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 struct platform_driver imx8mn_icc_driver = {
.probe = imx8mn_icc_probe,
.remove = imx_icc_unregister,
.driver = {
.name = "imx8mn-interconnect",
},
};
module_platform_driver(imx8mn_icc_driver);
MODULE_ALIAS("platform:imx8mn-interconnect");
MODULE_AUTHOR("Leonard Crestez <leonard.crestez@nxp.com>");
MODULE_DESCRIPTION("Interconnect framework driver for i.MX8MN SoC");
MODULE_LICENSE("GPL v2");
@@ -0,0 +1,254 @@
// 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/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 struct platform_driver imx8mp_icc_driver = {
.probe = imx8mp_icc_probe,
.remove = imx_icc_unregister,
.driver = {
.name = "imx8mp-interconnect",
},
};
module_platform_driver(imx8mp_icc_driver);
MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
MODULE_DESCRIPTION("Interconnect framework driver for i.MX8MP SoC");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:imx8mp-interconnect");
@@ -0,0 +1,101 @@
// 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 struct platform_driver imx8mq_icc_driver = {
.probe = imx8mq_icc_probe,
.remove = imx_icc_unregister,
.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_DESCRIPTION("Interconnect framework driver for i.MX8MQ SoC");
MODULE_LICENSE("GPL v2");