summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-07-16 07:22:21 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-07-16 07:22:21 +0200
commit6598a382bd34cce713d2dbe2aadd9496e7a7b643 (patch)
tree7853061ecfe3b38fe3865fda7ee85cb43d26aaf6
parenta8755e9bdd6a416331e286cc25cddbd93b2c064a (diff)
parent009c963eefa058384052d32d5b06fbc738195bdb (diff)
downloadlinux-6598a382bd34cce713d2dbe2aadd9496e7a7b643.tar.gz
linux-6598a382bd34cce713d2dbe2aadd9496e7a7b643.tar.bz2
linux-6598a382bd34cce713d2dbe2aadd9496e7a7b643.zip
Merge tag 'icc-5.20-rc1-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/djakov/icc into char-misc-next
Georgi writes: interconnect changes for 5.20 Here are the interconnect changes for the 5.20-rc1 merge window consisting of two new drivers, misc driver improvements and new device managed API. Core change: - Add device managed bulk API Driver changes: - New driver for NXP i.MX8MP platforms - New driver for Qualcomm SM6350 platforms - Multiple bucket support for Qualcomm RPM-based drivers. Signed-off-by: Georgi Djakov <djakov@kernel.org> * tag 'icc-5.20-rc1-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/djakov/icc: PM / devfreq: imx: Register i.MX8MP interconnect device interconnect: imx: Add platform driver for imx8mp interconnect: imx: configure NoC mode/prioriry/ext_control interconnect: imx: introduce imx_icc_provider interconnect: imx: set src node interconnect: imx: fix max_node_id interconnect: qcom: icc-rpm: Set bandwidth and clock for bucket values interconnect: qcom: icc-rpm: Support multiple buckets interconnect: qcom: icc-rpm: Change to use qcom_icc_xlate_extended() interconnect: qcom: Move qcom_icc_xlate_extended() to a common file dt-bindings: interconnect: Update property for icc-rpm path tag interconnect: icc-rpm: Set destination bandwidth as well as source bandwidth interconnect: qcom: msm8939: Use icc_sync_state interconnect: add device managed bulk API dt-bindings: interconnect: add fsl,imx8mp.h dt-bindings: interconnect: imx8m: Add bindings for imx8mp noc interconnect: qcom: Add SM6350 driver support dt-bindings: interconnect: Add Qualcomm SM6350 NoC support dt-bindings: interconnect: qcom: Split out rpmh-common bindings interconnect: qcom: icc-rpmh: Support child NoC device probe
-rw-r--r--Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml6
-rw-r--r--Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml6
-rw-r--r--Documentation/devicetree/bindings/interconnect/qcom,rpmh-common.yaml43
-rw-r--r--Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml22
-rw-r--r--Documentation/devicetree/bindings/interconnect/qcom,sm6350-rpmh.yaml82
-rw-r--r--drivers/devfreq/imx-bus.c1
-rw-r--r--drivers/interconnect/bulk.c42
-rw-r--r--drivers/interconnect/imx/Kconfig4
-rw-r--r--drivers/interconnect/imx/Makefile2
-rw-r--r--drivers/interconnect/imx/imx.c84
-rw-r--r--drivers/interconnect/imx/imx.h49
-rw-r--r--drivers/interconnect/imx/imx8mm.c2
-rw-r--r--drivers/interconnect/imx/imx8mn.c2
-rw-r--r--drivers/interconnect/imx/imx8mp.c259
-rw-r--r--drivers/interconnect/imx/imx8mq.c2
-rw-r--r--drivers/interconnect/qcom/Kconfig9
-rw-r--r--drivers/interconnect/qcom/Makefile5
-rw-r--r--drivers/interconnect/qcom/icc-common.c34
-rw-r--r--drivers/interconnect/qcom/icc-common.h13
-rw-r--r--drivers/interconnect/qcom/icc-rpm.c168
-rw-r--r--drivers/interconnect/qcom/icc-rpm.h6
-rw-r--r--drivers/interconnect/qcom/icc-rpmh.c30
-rw-r--r--drivers/interconnect/qcom/icc-rpmh.h1
-rw-r--r--drivers/interconnect/qcom/msm8939.c1
-rw-r--r--drivers/interconnect/qcom/sm6350.c493
-rw-r--r--drivers/interconnect/qcom/sm6350.h139
-rw-r--r--drivers/interconnect/qcom/sm8450.c1
-rw-r--r--include/dt-bindings/interconnect/fsl,imx8mp.h59
-rw-r--r--include/dt-bindings/interconnect/qcom,sm6350.h148
-rw-r--r--include/linux/interconnect.h7
30 files changed, 1627 insertions, 93 deletions
diff --git a/Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml b/Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml
index b8204ed22dd5..09c8948b5e25 100644
--- a/Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml
+++ b/Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml
@@ -26,14 +26,16 @@ properties:
oneOf:
- items:
- enum:
- - fsl,imx8mn-nic
- fsl,imx8mm-nic
+ - fsl,imx8mn-nic
+ - fsl,imx8mp-nic
- fsl,imx8mq-nic
- const: fsl,imx8m-nic
- items:
- enum:
- - fsl,imx8mn-noc
- fsl,imx8mm-noc
+ - fsl,imx8mn-noc
+ - fsl,imx8mp-noc
- fsl,imx8mq-noc
- const: fsl,imx8m-noc
- const: fsl,imx8m-nic
diff --git a/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml b/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml
index 8a676fef8c1d..4b37aa88a375 100644
--- a/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml
+++ b/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml
@@ -45,7 +45,11 @@ properties:
- qcom,sdm660-snoc
'#interconnect-cells':
- const: 1
+ description: |
+ Value: <1> is one cell in an interconnect specifier for the
+ interconnect node id, <2> requires the interconnect node id and an
+ extra path tag.
+ enum: [ 1, 2 ]
clocks:
minItems: 2
diff --git a/Documentation/devicetree/bindings/interconnect/qcom,rpmh-common.yaml b/Documentation/devicetree/bindings/interconnect/qcom,rpmh-common.yaml
new file mode 100644
index 000000000000..bbeb0541536b
--- /dev/null
+++ b/Documentation/devicetree/bindings/interconnect/qcom,rpmh-common.yaml
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interconnect/qcom,rpmh-common.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm RPMh Network-On-Chip Interconnect
+
+maintainers:
+ - Georgi Djakov <djakov@kernel.org>
+ - Bjorn Andersson <bjorn.andersson@linaro.org>
+
+description:
+ RPMh interconnect providers support system bandwidth requirements through
+ RPMh hardware accelerators known as Bus Clock Manager (BCM). The provider is
+ able to communicate with the BCM through the Resource State Coordinator (RSC)
+ associated with each execution environment. Provider nodes must point to at
+ least one RPMh device child node pertaining to their RSC and each provider
+ can map to multiple RPMh resources.
+
+properties:
+ '#interconnect-cells':
+ enum: [ 1, 2 ]
+
+ qcom,bcm-voters:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ items:
+ maxItems: 1
+ maxItems: 2
+ description:
+ List of phandles to qcom,bcm-voter nodes that are required by
+ this interconnect to send RPMh commands.
+
+ qcom,bcm-voter-names:
+ maxItems: 2
+ description:
+ Names for each of the qcom,bcm-voters specified.
+
+required:
+ - '#interconnect-cells'
+ - qcom,bcm-voters
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml
index 28b3516aa089..a429a1ed1006 100644
--- a/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml
+++ b/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml
@@ -18,6 +18,9 @@ description: |
least one RPMh device child node pertaining to their RSC and each provider
can map to multiple RPMh resources.
+allOf:
+ - $ref: qcom,rpmh-common.yaml#
+
properties:
reg:
maxItems: 1
@@ -130,28 +133,13 @@ properties:
- qcom,sm8450-pcie-anoc
- qcom,sm8450-system-noc
- '#interconnect-cells':
- enum: [ 1, 2 ]
-
- qcom,bcm-voters:
- $ref: /schemas/types.yaml#/definitions/phandle-array
- items:
- maxItems: 1
- description: |
- List of phandles to qcom,bcm-voter nodes that are required by
- this interconnect to send RPMh commands.
-
- qcom,bcm-voter-names:
- description: |
- Names for each of the qcom,bcm-voters specified.
+ '#interconnect-cells': true
required:
- compatible
- reg
- - '#interconnect-cells'
- - qcom,bcm-voters
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/interconnect/qcom,sm6350-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,sm6350-rpmh.yaml
new file mode 100644
index 000000000000..49eb156b08e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/interconnect/qcom,sm6350-rpmh.yaml
@@ -0,0 +1,82 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interconnect/qcom,sm6350-rpmh.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SM6350 RPMh Network-On-Chip Interconnect
+
+maintainers:
+ - Luca Weiss <luca.weiss@fairphone.com>
+
+description:
+ Qualcomm RPMh-based interconnect provider on SM6350.
+
+allOf:
+ - $ref: qcom,rpmh-common.yaml#
+
+properties:
+ compatible:
+ enum:
+ - qcom,sm6350-aggre1-noc
+ - qcom,sm6350-aggre2-noc
+ - qcom,sm6350-config-noc
+ - qcom,sm6350-dc-noc
+ - qcom,sm6350-gem-noc
+ - qcom,sm6350-mmss-noc
+ - qcom,sm6350-npu-noc
+ - qcom,sm6350-system-noc
+
+ reg:
+ maxItems: 1
+
+ '#interconnect-cells': true
+
+patternProperties:
+ '^interconnect-[a-z0-9\-]+$':
+ type: object
+ description:
+ The interconnect providers do not have a separate QoS register space,
+ but share parent's space.
+ $ref: qcom,rpmh-common.yaml#
+
+ properties:
+ compatible:
+ enum:
+ - qcom,sm6350-clk-virt
+ - qcom,sm6350-compute-noc
+
+ '#interconnect-cells': true
+
+ required:
+ - compatible
+
+ unevaluatedProperties: false
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ config_noc: interconnect@1500000 {
+ compatible = "qcom,sm6350-config-noc";
+ reg = <0x01500000 0x28000>;
+ #interconnect-cells = <2>;
+ qcom,bcm-voters = <&apps_bcm_voter>;
+ };
+
+ system_noc: interconnect@1620000 {
+ compatible = "qcom,sm6350-system-noc";
+ reg = <0x01620000 0x17080>;
+ #interconnect-cells = <2>;
+ qcom,bcm-voters = <&apps_bcm_voter>;
+
+ clk_virt: interconnect-clk-virt {
+ compatible = "qcom,sm6350-clk-virt";
+ #interconnect-cells = <2>;
+ qcom,bcm-voters = <&apps_bcm_voter>;
+ };
+ };
diff --git a/drivers/devfreq/imx-bus.c b/drivers/devfreq/imx-bus.c
index f3f6e25053ed..afb552198937 100644
--- a/drivers/devfreq/imx-bus.c
+++ b/drivers/devfreq/imx-bus.c
@@ -145,6 +145,7 @@ static const struct of_device_id imx_bus_of_match[] = {
{ .compatible = "fsl,imx8mq-noc", .data = "imx8mq-interconnect", },
{ .compatible = "fsl,imx8mm-noc", .data = "imx8mm-interconnect", },
{ .compatible = "fsl,imx8mn-noc", .data = "imx8mn-interconnect", },
+ { .compatible = "fsl,imx8mp-noc", .data = "imx8mp-interconnect", },
{ .compatible = "fsl,imx8m-noc", },
{ .compatible = "fsl,imx8m-nic", },
{ /* sentinel */ },
diff --git a/drivers/interconnect/bulk.c b/drivers/interconnect/bulk.c
index 448cc536aa79..8b1d8a412464 100644
--- a/drivers/interconnect/bulk.c
+++ b/drivers/interconnect/bulk.c
@@ -115,3 +115,45 @@ void icc_bulk_disable(int num_paths, const struct icc_bulk_data *paths)
icc_disable(paths[num_paths].path);
}
EXPORT_SYMBOL_GPL(icc_bulk_disable);
+
+struct icc_bulk_devres {
+ struct icc_bulk_data *paths;
+ int num_paths;
+};
+
+static void devm_icc_bulk_release(struct device *dev, void *res)
+{
+ struct icc_bulk_devres *devres = res;
+
+ icc_bulk_put(devres->num_paths, devres->paths);
+}
+
+/**
+ * devm_of_icc_bulk_get() - resource managed of_icc_bulk_get
+ * @dev: the device requesting the path
+ * @num_paths: the number of icc_bulk_data
+ * @paths: the table with the paths we want to get
+ *
+ * Returns 0 on success or negative errno otherwise.
+ */
+int devm_of_icc_bulk_get(struct device *dev, int num_paths, struct icc_bulk_data *paths)
+{
+ struct icc_bulk_devres *devres;
+ int ret;
+
+ devres = devres_alloc(devm_icc_bulk_release, sizeof(*devres), GFP_KERNEL);
+ if (!devres)
+ return -ENOMEM;
+
+ ret = of_icc_bulk_get(dev, num_paths, paths);
+ if (!ret) {
+ devres->paths = paths;
+ devres->num_paths = num_paths;
+ devres_add(dev, devres);
+ } else {
+ devres_free(devres);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devm_of_icc_bulk_get);
diff --git a/drivers/interconnect/imx/Kconfig b/drivers/interconnect/imx/Kconfig
index be2928362bb7..c772552431f5 100644
--- a/drivers/interconnect/imx/Kconfig
+++ b/drivers/interconnect/imx/Kconfig
@@ -15,3 +15,7 @@ config INTERCONNECT_IMX8MN
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
index 21fd5233754f..16d256cdeab4 100644
--- a/drivers/interconnect/imx/Makefile
+++ b/drivers/interconnect/imx/Makefile
@@ -2,8 +2,10 @@ 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
index 249ca25d1d55..48ffd59953bf 100644
--- a/drivers/interconnect/imx/imx.c
+++ b/drivers/interconnect/imx/imx.c
@@ -10,6 +10,7 @@
#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>
@@ -21,8 +22,10 @@
/* 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)
@@ -37,8 +40,30 @@ 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;
@@ -61,6 +86,12 @@ static int imx_icc_node_set(struct icc_node *node)
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);
}
@@ -128,9 +159,11 @@ static int imx_icc_node_init_qos(struct icc_provider *provider,
DEV_PM_QOS_MIN_FREQUENCY, 0);
}
-static struct icc_node *imx_icc_node_add(struct icc_provider *provider,
- const struct imx_icc_node_desc *node_desc)
+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;
@@ -157,6 +190,8 @@ static struct icc_node *imx_icc_node_add(struct icc_provider *provider,
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) {
@@ -178,10 +213,12 @@ static void imx_icc_unregister_nodes(struct icc_provider *provider)
imx_icc_node_destroy(node);
}
-static int imx_icc_register_nodes(struct icc_provider *provider,
+static int imx_icc_register_nodes(struct imx_icc_provider *imx_provider,
const struct imx_icc_node_desc *descs,
- int count)
+ 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;
@@ -191,7 +228,8 @@ static int imx_icc_register_nodes(struct icc_provider *provider,
const struct imx_icc_node_desc *node_desc = &descs[i];
size_t j;
- node = imx_icc_node_add(provider, node_desc);
+ 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);
@@ -229,32 +267,44 @@ static int get_max_node_id(struct imx_icc_node_desc *nodes, int nodes_count)
}
int imx_icc_register(struct platform_device *pdev,
- struct imx_icc_node_desc *nodes, int nodes_count)
+ 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 max_node_id;
+ int num_nodes;
int ret;
/* icc_onecell_data is indexed by node_id, unlike nodes param */
- max_node_id = get_max_node_id(nodes, nodes_count);
- data = devm_kzalloc(dev, struct_size(data, nodes, max_node_id),
+ 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 = max_node_id;
+ data->num_nodes = num_nodes;
- provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL);
- if (!provider)
+ 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;
- platform_set_drvdata(pdev, 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 = icc_provider_add(provider);
if (ret) {
@@ -262,7 +312,7 @@ int imx_icc_register(struct platform_device *pdev,
return ret;
}
- ret = imx_icc_register_nodes(provider, nodes, nodes_count);
+ ret = imx_icc_register_nodes(imx_provider, nodes, nodes_count, settings);
if (ret)
goto provider_del;
@@ -276,11 +326,11 @@ EXPORT_SYMBOL_GPL(imx_icc_register);
int imx_icc_unregister(struct platform_device *pdev)
{
- struct icc_provider *provider = platform_get_drvdata(pdev);
+ struct imx_icc_provider *imx_provider = platform_get_drvdata(pdev);
- imx_icc_unregister_nodes(provider);
+ imx_icc_unregister_nodes(&imx_provider->provider);
- return icc_provider_del(provider);
+ return icc_provider_del(&imx_provider->provider);
}
EXPORT_SYMBOL_GPL(imx_icc_unregister);
diff --git a/drivers/interconnect/imx/imx.h b/drivers/interconnect/imx/imx.h
index 75da51076c68..e0a2ee173ecd 100644
--- a/drivers/interconnect/imx/imx.h
+++ b/drivers/interconnect/imx/imx.h
@@ -10,11 +10,43 @@
#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 {
@@ -38,6 +70,20 @@ struct imx_icc_node_desc {
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, \
@@ -55,7 +101,8 @@ struct imx_icc_node_desc {
int imx_icc_register(struct platform_device *pdev,
struct imx_icc_node_desc *nodes,
- int nodes_count);
+ int nodes_count,
+ struct imx_icc_noc_setting *noc_settings);
int 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
index 1083490bb391..ae797412db96 100644
--- a/drivers/interconnect/imx/imx8mm.c
+++ b/drivers/interconnect/imx/imx8mm.c
@@ -83,7 +83,7 @@ static struct imx_icc_node_desc nodes[] = {
static int imx8mm_icc_probe(struct platform_device *pdev)
{
- return imx_icc_register(pdev, nodes, ARRAY_SIZE(nodes));
+ return imx_icc_register(pdev, nodes, ARRAY_SIZE(nodes), NULL);
}
static int imx8mm_icc_remove(struct platform_device *pdev)
diff --git a/drivers/interconnect/imx/imx8mn.c b/drivers/interconnect/imx/imx8mn.c
index ad97e55fd4e5..1ce94c5bdd8c 100644
--- a/drivers/interconnect/imx/imx8mn.c
+++ b/drivers/interconnect/imx/imx8mn.c
@@ -72,7 +72,7 @@ static struct imx_icc_node_desc nodes[] = {
static int imx8mn_icc_probe(struct platform_device *pdev)
{
- return imx_icc_register(pdev, nodes, ARRAY_SIZE(nodes));
+ return imx_icc_register(pdev, nodes, ARRAY_SIZE(nodes), NULL);
}
static int imx8mn_icc_remove(struct platform_device *pdev)
diff --git a/drivers/interconnect/imx/imx8mp.c b/drivers/interconnect/imx/imx8mp.c
new file mode 100644
index 000000000000..5f1c83ed157b
--- /dev/null
+++ b/drivers/interconnect/imx/imx8mp.c
@@ -0,0 +1,259 @@
+// 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,