Skip to contentSkip to conversation

interconnect: Add imx support via devfreq

PATCH Superseded Leonard Crestez 5 participants 21 messages Mar 26, 2020 – Apr 3, 2020

Subsystems (4)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover interconnect: Add imx support via devfreq

This series adds interconnect scaling support for imx8m series chips. It uses a per-SOC interconnect provider layered on top of multiple instances of devfreq for scalable nodes along the interconnect.

Existing qcom interconnect providers mostly translate bandwidth requests into firmware calls but equivalent firmware on imx8m is much thinner. Scaling support for individual nodes is implemented as distinct devfreq drivers instead.

The imx interconnect provider doesn't communicate with devfreq directly but rather computes "minimum frequencies" for nodes along the path and creates dev_pm_qos requests.

Since there is no single devicetree node that can represent the "interconnect" the main NOC is picked as the "interconnect provider" and will probe the interconnect platform device if #interconnect-cells is present. This avoids introducing "virtual" devices but it means that DT bindings of main NOC includes properties for both devfreq and interconnect.

Only the ddrc and main noc are scalable right now but more can be added.

Also available on a github branch (with various unrelated changes):
https://github.com/cdleonard/linux/tree/next
Testing currently requires NXP branch of atf+uboot

Martin: I believe you should be able to use this to control DRAM frequency from video by just adding interconnect consumer code to nwl-dsi. Sample code:

	https://github.com/cdleonard/linux/commit/43772762aa5045f1ce5623740f9a4baef988d083
	https://github.com/cdleonard/linux/commit/7b601e981b1f517b5d98b43bde292972ded13086

Changes since RFCv6:
* Replace scalable-nodes stuff with just a fsl,ddrc property. Future scalable nodes can be added as additional phandles on the NOC
* Allow building interconnect drivers as modules
* Handle icc_provider_del errors in imx_icc_unregister (like EBUSY).
* Rename imx-devfreq to imx-bus, similar to exynos-bus
* Explain why imx bus clock enabling is not required
* All dependencies accepted (some time ago).

Changes since RFCv5:
* Replace scanning for interconnect-node-id with explicit scalable-nodes/scalable-node-ids property on NoC.
* Now passes make dtbs_check
* Remove struct imx_icc_provider
* Switch to of_icc_xlate_onecell
* Use of_find_device_by_node to fetch QoS target, this causes fewer probe deferrals, removes dependency on devfreq API and even allows reloading ddrc module at runtime
* Add imx_icc_node_destroy helper
* Remove 0/1 on DEFINE_BUS_SLAVE/MASTER which created spurious links

Changes since RFCv4:
* Drop icc proxy nonsense
* Make devfreq driver for NOC probe the ICC driver if #interconnect-cells is present
* Move NOC support to interconnect series and rename the node in DT
* Add support for all chips at once, differences are not intereseting and there is more community interest for 8mq than 8mm.

Changes since RFCv3:
* Remove the virtual "icc" node and add devfreq nodes as proxy providers
* Fix build on 32-bit arm (reported by kbuilt test robot)
* Remove ARCH_MXC_ARM64 (never existed in upstream)
* Remove _numlinks, calculate instead
* Replace __BUSFREQ_H header guard
* Improve commit message and comment spelling
* Fix checkpatch issues
Link to RFCv3: https://patchwork.kernel.org/cover/11078671/

Changes since RFCv2 and initial work by Alexandre Bailon:
* Relying on devfreq and dev_pm_qos instead of CLK
* No more "platform opp" stuff
* No more special suspend handling: use suspend-opp on devfreq instead
* Replace all mentions of "busfreq" with "interconnect" Link to v2: https://patchwork.kernel.org/cover/11021563/

Leonard Crestez (8):
dt-bindings: interconnect: Add bindings for imx8m noc PM / devfreq: Add generic imx bus scaling driver PM / devfreq: imx: Register interconnect device
interconnect: Add imx core driver
interconnect: imx: Add platform driver for imx8mm
interconnect: imx: Add platform driver for imx8mq
interconnect: imx: Add platform driver for imx8mn
arm64: dts: imx8m: Add NOC nodes

 .../bindings/interconnect/fsl,imx8m-noc.yaml  | 138 ++++++++
 arch/arm64/boot/dts/freescale/imx8mm.dtsi     |  24 ++
 arch/arm64/boot/dts/freescale/imx8mn.dtsi     |  24 ++
 arch/arm64/boot/dts/freescale/imx8mq.dtsi     |  24 ++
 drivers/devfreq/Kconfig                       |   9 +
 drivers/devfreq/Makefile                      |   1 +
 drivers/devfreq/imx-bus.c                     | 181 +++++++++++
 drivers/interconnect/Kconfig                  |   1 +
 drivers/interconnect/Makefile                 |   1 +
 drivers/interconnect/imx/Kconfig              |  17 +
 drivers/interconnect/imx/Makefile             |   9 +
 drivers/interconnect/imx/imx.c                | 298 ++++++++++++++++++
 drivers/interconnect/imx/imx.h                |  62 ++++
 drivers/interconnect/imx/imx8mm.c             | 108 +++++++
 drivers/interconnect/imx/imx8mn.c             |  97 ++++++
 drivers/interconnect/imx/imx8mq.c             | 106 +++++++
 include/dt-bindings/interconnect/imx8mm.h     |  49 +++
 include/dt-bindings/interconnect/imx8mn.h     |  41 +++
 include/dt-bindings/interconnect/imx8mq.h     |  48 +++
 19 files changed, 1238 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml
 create mode 100644 drivers/devfreq/imx-bus.c
 create mode 100644 drivers/interconnect/imx/Kconfig
 create mode 100644 drivers/interconnect/imx/Makefile
 create mode 100644 drivers/interconnect/imx/imx.c
 create mode 100644 drivers/interconnect/imx/imx.h
 create mode 100644 drivers/interconnect/imx/imx8mm.c
 create mode 100644 drivers/interconnect/imx/imx8mn.c
 create mode 100644 drivers/interconnect/imx/imx8mq.c
 create mode 100644 include/dt-bindings/interconnect/imx8mm.h
 create mode 100644 include/dt-bindings/interconnect/imx8mn.h
 create mode 100644 include/dt-bindings/interconnect/imx8mq.h
Signature · 1 line
2.17.1
#1 lore raw

PATCH 1/8 dt-bindings: interconnect: Add bindings for imx8m noc

Add initial dt bindings for the interconnects inside i.MX chips. Multiple external IPs are involved but SOC integration means the software controllable interfaces are very similar.

Main NOC node acts as interconnect provider if #interconnect-cells is present. Currently there is a single imx interconnect provider for the whole SOC.

Other pieces of scalable interconnects can be present, each with their own OPP table.

---
 .../bindings/interconnect/fsl,imx8m-noc.yaml  | 138 ++++++++++++++++++
 1 file changed, 138 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml
Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml new file +138 -0
new file mode 100644
index 000000000000..6c192f1c0edd
@@ -0,0 +1,138 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interconnect/fsl,imx8m-noc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic i.MX bus frequency device
+
+maintainers:
+  - Leonard Crestez <[email protected]>
+
+description: |
+  The i.MX SoC family has multiple buses for which clock frequency (and
+  sometimes voltage) can be adjusted.
+
+  Some of those buses expose register areas mentioned in the memory maps as GPV
+  ("Global Programmers View") but not all. Access to this area might be denied
+  for normal (non-secure) world.
+
+  The buses are based on externally licensed IPs such as ARM NIC-301 and
+  Arteris FlexNOC but DT bindings are specific to the integration of these bus
+  interconnect IPs into imx SOCs.
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+        - enum:
+          - fsl,imx8mn-nic
+          - fsl,imx8mm-nic
+          - fsl,imx8mq-nic
+        - const: fsl,imx8m-nic
+      - items:
+        - enum:
+          - fsl,imx8mn-noc
+          - fsl,imx8mm-noc
+          - fsl,imx8mq-noc
+        - const: fsl,imx8m-noc
+      - const: fsl, imx8m-nic
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  operating-points-v2: true
+  opp-table: true
+
+  fsl,ddrc:
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+    description:
+      Phandle to DDR Controller.
+
+  '#interconnect-cells':
+    description:
+      If specified then also act as an interconnect provider. Should only be
+      set once per soc on the main noc.
+    const: 1
+
+required:
+  - compatible
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+#include <dt-bindings/clock/imx8mm-clock.h>
+#include <dt-bindings/interconnect/imx8mm.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+noc: interconnect@32700000 {
+        compatible = "fsl,imx8mm-noc", "fsl,imx8m-noc";
+        reg = <0x32700000 0x100000>;
+        clocks = <&clk IMX8MM_CLK_NOC>;
+        #interconnect-cells = <1>;
+
+        /* Used to make requests for DEV_PM_QOS_MIN_FREQUENCY: */
+        fsl,scalable-node-ids = <IMX8MM_ICN_NOC>,
+                                <IMX8MM_ICN_MIPI>,
+                                <IMX8MM_ICS_DRAM>;
+        fsl,scalable-nodes = <&noc>,
+                             <&pl301_mipi>,
+                             <&ddrc>;
+
+        /* For passive governor: */
+        devfreq = <&ddrc>;
+
+        operating-points-v2 = <&noc_opp_table>;
+        noc_opp_table: opp-table {
+                compatible = "operating-points-v2";
+
+                opp-133M {
+                        opp-hz = /bits/ 64 <133333333>;
+                };
+                opp-800M {
+                        opp-hz = /bits/ 64 <800000000>;
+                };
+        };
+};
+
+pl301_mipi: interconnect@32500000 {
+        compatible = "fsl,imx8m-nic";
+        reg = <0x32500000 0x100000>;
+        clocks = <&clk IMX8MM_CLK_DISP_AXI>;
+        operating-points-v2 = <&pl301_mipi_opp_table>;
+
+        pl301_mipi_opp_table: opp-table {
+                compatible = "operating-points-v2";
+
+                opp-200M {
+                        opp-hz = /bits/ 64 <200000000>;
+                };
+                opp-500M {
+                        opp-hz = /bits/ 64 <500000000>;
+                };
+        };
+};
+
+ddrc: memory-controller@3d400000 {
+        compatible = "fsl,imx8mm-ddrc", "fsl,imx8m-ddrc";
+        reg = <0x3d400000 0x400000>;
+        glock-names = "core", "pll", "alt", "apb";
+        clocks = <&clk IMX8MM_CLK_DRAM_CORE>,
+                 <&clk IMX8MM_DRAM_PLL>,
+                 <&clk IMX8MM_CLK_DRAM_ALT>,
+                 <&clk IMX8MM_CLK_DRAM_APB>;
+        /* For ondemand governor: */
+        devfreq-events = <&ddr_pmu>;
+};
+
+ddr_pmu: ddr-pmu@3d800000 {
+        compatible = "fsl,imx8mm-ddr-pmu", "fsl,imx8m-ddr-pmu";
+        reg = <0x3d800000 0x400000>;
+        interrupt-parent = <&gic>;
+        interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+};
Signature · 1 line
2.17.1
maintainer
#2 lore raw

Re: [PATCH 1/8] dt-bindings: interconnect: Add bindings for imx8m noc

Quoted 8 lines · Leonard Crestez

Add initial dt bindings for the interconnects inside i.MX chips. Multiple external IPs are involved but SOC integration means the software controllable interfaces are very similar.

Main NOC node acts as interconnect provider if #interconnect-cells is present. Currently there is a single imx interconnect provider for the whole SOC.

Quoted 9 lines

Other pieces of scalable interconnects can be present, each with their own OPP table.

---
 .../bindings/interconnect/fsl,imx8m-noc.yaml  | 138 ++++++++++++++++++
 1 file changed, 138 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml

My bot found errors running 'make dt_binding_check' on your patch:

Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml: while parsing a block mapping
in "<unicode string>", line 4, column 1
did not find expected key
in "<unicode string>", line 79, column 9
Documentation/devicetree/bindings/Makefile:12: recipe for target 'Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.example.dts' failed make[1]: *** [Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.example.dts] Error 1
make[1]: *** Waiting for unfinished jobs....
Makefile:1262: recipe for target 'dt_binding_check' failed
make: *** [dt_binding_check] Error 2

See https://patchwork.ozlabs.org/patch/1261720

If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure dt-schema is up to date:

pip3 install git+https://github.com/devicetree-org/dt-schema.git@master --upgrade

Please check and re-submit.

#3 lore raw

PATCH 2/8 PM / devfreq: Add generic imx bus scaling driver

In reply to Leonard Crestez

Add initial support for dynamic frequency switching on pieces of the imx interconnect fabric.

All this driver does is set a clk rate based on an opp table, it does not map register areas.

---
 drivers/devfreq/Kconfig   |   9 +++
 drivers/devfreq/Makefile  |   1 +
 drivers/devfreq/imx-bus.c | 142 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 152 insertions(+)
 create mode 100644 drivers/devfreq/imx-bus.c
drivers/devfreq/Kconfig +9 -0
index 0b1df12e0f21..44d26192ddc4 100644
@@ -99,10 +99,19 @@ config ARM_IMX8M_DDRC_DEVFREQ
 	select DEVFREQ_GOV_USERSPACE
 	help
 	  This adds the DEVFREQ driver for the i.MX8M DDR Controller. It allows
 	  adjusting DRAM frequency.
 
+config ARM_IMX_BUS_DEVFREQ
+	tristate "i.MX Generic Bus DEVFREQ Driver"
+	depends on ARCH_MXC || COMPILE_TEST
+	select DEVFREQ_GOV_PASSIVE
+	select DEVFREQ_GOV_USERSPACE
+	help
+	  This adds the generic DEVFREQ driver for i.MX interconnects. It
+	  allows adjusting NIC/NOC frequency.
+
 config ARM_TEGRA_DEVFREQ
 	tristate "NVIDIA Tegra30/114/124/210 DEVFREQ Driver"
 	depends on ARCH_TEGRA_3x_SOC || ARCH_TEGRA_114_SOC || \
 		ARCH_TEGRA_132_SOC || ARCH_TEGRA_124_SOC || \
 		ARCH_TEGRA_210_SOC || \
drivers/devfreq/Makefile +1 -0
index 3eb4d5e6635c..3ca1ad0ecb97 100644
@@ -7,10 +7,11 @@ obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)	+= governor_powersave.o
 obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)	+= governor_userspace.o
 obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)	+= governor_passive.o
 
 # DEVFREQ Drivers
 obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)	+= exynos-bus.o
+obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ)	+= imx-bus.o
 obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ)	+= imx8m-ddrc.o
 obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)	+= rk3399_dmc.o
 obj-$(CONFIG_ARM_TEGRA_DEVFREQ)		+= tegra30-devfreq.o
 obj-$(CONFIG_ARM_TEGRA20_DEVFREQ)	+= tegra20-devfreq.o
 
drivers/devfreq/imx-bus.c new file +142 -0

142 lines not on this page · raw message

Signature · 1 line
2.17.1
maintainer
#4 lore raw

Re: [PATCH 2/8] PM / devfreq: Add generic imx bus scaling driver

Hi,

Looks good to me. I added the comments.
But, it need to add the dt binding documentation for this device.

The old email of Artur Świgoń is not used. On next time,
use following the new email address Because when I reply the mail, always show the fail message from thunderbird due to the Artur's old email. <[email protected]> -> <[email protected]>

Quoted 19 lines · Leonard Crestez

Add initial support for dynamic frequency switching on pieces of the imx interconnect fabric.

All this driver does is set a clk rate based on an opp table, it does not map register areas.

---
 drivers/devfreq/Kconfig   |   9 +++
 drivers/devfreq/Makefile  |   1 +
 drivers/devfreq/imx-bus.c | 142 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 152 insertions(+)
 create mode 100644 drivers/devfreq/imx-bus.c
drivers/devfreq/Kconfig +0 -0
index 0b1df12e0f21..44d26192ddc4 100644

drivers/devfreq/Kconfig config ARM_IMX8M_DDRC_DEVFREQ · line 108

Quoted 10 lines
drivers/devfreq/Kconfig +5 -0
@@ -99,10 +99,19 @@ config ARM_IMX8M_DDRC_DEVFREQ
 	select DEVFREQ_GOV_USERSPACE
 	help
 	  This adds the DEVFREQ driver for the i.MX8M DDR Controller. It allows
 	  adjusting DRAM frequency.
 
+config ARM_IMX_BUS_DEVFREQ
+	tristate "i.MX Generic Bus DEVFREQ Driver"
+	depends on ARCH_MXC || COMPILE_TEST
+	select DEVFREQ_GOV_PASSIVE
+	select DEVFREQ_GOV_USERSPACE

Maybe, you would update it by using passive governor? But, in this version, it doesn't handle the any passive governor.

Quoted 14 lines
drivers/devfreq/Kconfig +4 -0
+	help
+	  This adds the generic DEVFREQ driver for i.MX interconnects. It
+	  allows adjusting NIC/NOC frequency.
+
 config ARM_TEGRA_DEVFREQ
 	tristate "NVIDIA Tegra30/114/124/210 DEVFREQ Driver"
 	depends on ARCH_TEGRA_3x_SOC || ARCH_TEGRA_114_SOC || \
 		ARCH_TEGRA_132_SOC || ARCH_TEGRA_124_SOC || \
 		ARCH_TEGRA_210_SOC || \
drivers/devfreq/Makefile +0 -0
index 3eb4d5e6635c..3ca1ad0ecb97 100644

drivers/devfreq/Makefile obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o · line 12

Quoted 6 lines
drivers/devfreq/Makefile +1 -0
@@ -7,10 +7,11 @@ obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)	+= governor_powersave.o
 obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)	+= governor_userspace.o
 obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)	+= governor_passive.o
 
 # DEVFREQ Drivers
 obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)	+= exynos-bus.o
+obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ)	+= imx-bus.o

The ARM_IMX_BUS_DEVFREQ config is under ARM_IMX8M_DDRC_DEVFREQ and imx-bus.o is over imx8m-ddrc.o. Need to edit the sequence.

Quoted 20 lines
drivers/devfreq/Makefile +0 -0
 obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ)	+= imx8m-ddrc.o
 obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)	+= rk3399_dmc.o
 obj-$(CONFIG_ARM_TEGRA_DEVFREQ)		+= tegra30-devfreq.o
 obj-$(CONFIG_ARM_TEGRA20_DEVFREQ)	+= tegra20-devfreq.o
 
drivers/devfreq/imx-bus.c new file +9 -0
new file mode 100644
index 000000000000..285e0f1ae6b1
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <linux/clk.h>
+#include <linux/devfreq.h>
+#include <linux/device.h>
+#include <linux/module.h>

drivers/devfreq/imx-bus.c line 19

Quoted 10 lines
drivers/devfreq/imx-bus.c new file +10 -0
+#include <linux/of_device.h>
+#include <linux/pm_opp.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+struct imx_bus {
+	struct devfreq_dev_profile profile;
+	struct devfreq *devfreq;
+	struct clk *clk;
+	struct devfreq_passive_data passive_data;

This patch doesn't touch the passive_data.

Quoted 7 lines
drivers/devfreq/imx-bus.c new file +7 -0
+};
+
+static int imx_bus_target(struct device *dev,
+		unsigned long *freq, u32 flags)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+	struct dev_pm_opp *new_opp;

drivers/devfreq/imx-bus.c line 36

Quoted 10 lines
drivers/devfreq/imx-bus.c new file +10 -0
+	unsigned long new_freq;
+	int ret;
+
+	new_opp = devfreq_recommended_opp(dev, freq, flags);
+	if (IS_ERR(new_opp)) {
+		ret = PTR_ERR(new_opp);
+		dev_err(dev, "failed to get recommended opp: %d\n", ret);
+		return ret;
+	}
+	new_freq = dev_pm_opp_get_freq(new_opp);

It doesn't need. Because the new frequency is stored to 'freq' by calling devfreq_recommended_opp().

drivers/devfreq/imx-bus.c line 39

Quoted 3 lines
drivers/devfreq/imx-bus.c new file +3 -0
+	dev_pm_opp_put(new_opp);
+
+	return clk_set_rate(priv->clk, new_freq);

nitpick. you can use dev_pm_opp_set_rate(). But, I'm not forcing to use it.

Quoted 31 lines
drivers/devfreq/imx-bus.c new file +31 -0
+}
+
+static int imx_bus_get_cur_freq(struct device *dev, unsigned long *freq)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+
+	*freq = clk_get_rate(priv->clk);
+
+	return 0;
+}
+
+static int imx_bus_get_dev_status(struct device *dev,
+		struct devfreq_dev_status *stat)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+
+	stat->busy_time = 0;
+	stat->total_time = 0;
+	stat->current_frequency = clk_get_rate(priv->clk);
+
+	return 0;
+}
+
+static void imx_bus_exit(struct device *dev)
+{
+	dev_pm_opp_of_remove_table(dev);
+}
+
+static int imx_bus_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;

drivers/devfreq/imx-bus.c line 80

Quoted 10 lines
drivers/devfreq/imx-bus.c new file +10 -0
+	struct imx_bus *priv;
+	const char *gov = DEVFREQ_GOV_USERSPACE;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	/*
+	 * Fetch the clock to adjust but don't explictly enable.

Need to fix typo.
s/explictly/explicitly

Quoted 63 lines
drivers/devfreq/imx-bus.c new file +62 -0
+	 *
+	 * For imx bus clock clk_set_rate is safe no matter if the clock is on
+	 * or off and some peripheral side-buses might be off unless enabled by
+	 * drivers for devices on those specific buses.
+	 *
+	 * Rate adjustment on a disabled bus clock just takes effect later.
+	 */
+	priv->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(priv->clk)) {
+		ret = PTR_ERR(priv->clk);
+		dev_err(dev, "failed to fetch clk: %d\n", ret);
+		return ret;
+	}
+	platform_set_drvdata(pdev, priv);
+
+	ret = dev_pm_opp_of_add_table(dev);
+	if (ret < 0) {
+		dev_err(dev, "failed to get OPP table\n");
+		return ret;
+	}
+
+	priv->profile.polling_ms = 1000;
+	priv->profile.target = imx_bus_target;
+	priv->profile.get_dev_status = imx_bus_get_dev_status;
+	priv->profile.exit = imx_bus_exit;
+	priv->profile.get_cur_freq = imx_bus_get_cur_freq;
+	priv->profile.initial_freq = clk_get_rate(priv->clk);
+
+	priv->devfreq = devm_devfreq_add_device(dev, &priv->profile,
+						gov, NULL);
+	if (IS_ERR(priv->devfreq)) {
+		ret = PTR_ERR(priv->devfreq);
+		dev_err(dev, "failed to add devfreq device: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	dev_pm_opp_of_remove_table(dev);
+	return ret;
+}
+
+static const struct of_device_id imx_bus_of_match[] = {
+	{ .compatible = "fsl,imx8m-noc", },
+	{ .compatible = "fsl,imx8m-nic", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_bus_of_match);
+
+static struct platform_driver imx_bus_platdrv = {
+	.probe		= imx_bus_probe,
+	.driver = {
+		.name	= "imx-bus-devfreq",
+		.of_match_table = of_match_ptr(imx_bus_of_match),
+	},
+};
+module_platform_driver(imx_bus_platdrv);
+
+MODULE_DESCRIPTION("Generic i.MX bus frequency scaling driver");
+MODULE_AUTHOR("Leonard Crestez <[email protected]>");
+MODULE_LICENSE("GPL v2");
Signature · 3 lines
Best Regards,
Chanwoo Choi
Samsung Electronics
#5 lore raw

Re: [PATCH 2/8] PM / devfreq: Add generic imx bus scaling driver

Quoted 4 lines · Chanwoo Choi

Hi,

Looks good to me. I added the comments.
But, it need to add the dt binding documentation for this device.

DT bindings were included:

https://patchwork.kernel.org/patch/11458981/

Quoted 4 lines

The old email of Artur Świgoń is not used. On next time,
use following the new email address Because when I reply the mail, always show the fail message from thunderbird due to the Artur's old email. <[email protected]> -> <[email protected]>

Yeah, I received multiple bounces because of this.

Quoted 25 lines · Leonard Crestez
Quoted 24 lines

Add initial support for dynamic frequency switching on pieces of the imx interconnect fabric.

All this driver does is set a clk rate based on an opp table, it does not map register areas.

---
  drivers/devfreq/Kconfig   |   9 +++
  drivers/devfreq/Makefile  |   1 +
  drivers/devfreq/imx-bus.c | 142 ++++++++++++++++++++++++++++++++++++++
  3 files changed, 152 insertions(+)

create mode 100644 drivers/devfreq/imx-bus.c

drivers/devfreq/Kconfig +0 -0
index 0b1df12e0f21..44d26192ddc4 100644
@@ -99,10 +99,19 @@ config ARM_IMX8M_DDRC_DEVFREQ
  	select DEVFREQ_GOV_USERSPACE
  	help
  	  This adds the DEVFREQ driver for the i.MX8M DDR Controller. It allows
  	  adjusting DRAM frequency.
 
Quoted 8 lines

drivers/devfreq/Kconfig config ARM_IMX8M_DDRC_DEVFREQ · line 108

Quoted 5 lines
drivers/devfreq/Kconfig +5 -0
+config ARM_IMX_BUS_DEVFREQ
+	tristate "i.MX Generic Bus DEVFREQ Driver"
+	depends on ARCH_MXC || COMPILE_TEST
+	select DEVFREQ_GOV_PASSIVE
+	select DEVFREQ_GOV_USERSPACE

Maybe, you would update it by using passive governor? But, in this version, it doesn't handle the any passive governor.

dropped

Quoted 17 lines
Quoted 17 lines
drivers/devfreq/Kconfig +4 -0
+	help
+	  This adds the generic DEVFREQ driver for i.MX interconnects. It
+	  allows adjusting NIC/NOC frequency.
+
  config ARM_TEGRA_DEVFREQ
  	tristate "NVIDIA Tegra30/114/124/210 DEVFREQ Driver"
  	depends on ARCH_TEGRA_3x_SOC || ARCH_TEGRA_114_SOC || \
  		ARCH_TEGRA_132_SOC || ARCH_TEGRA_124_SOC || \
  		ARCH_TEGRA_210_SOC || \
drivers/devfreq/Makefile +0 -0
index 3eb4d5e6635c..3ca1ad0ecb97 100644
@@ -7,10 +7,11 @@ obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)	+= governor_powersave.o
  obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)	+= governor_userspace.o
  obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)	+= governor_passive.o
 
Quoted 6 lines

drivers/devfreq/Makefile obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o · line 12

Quoted 3 lines
drivers/devfreq/Makefile +1 -0
  # DEVFREQ Drivers
  obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)	+= exynos-bus.o
+obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ)	+= imx-bus.o

The ARM_IMX_BUS_DEVFREQ config is under ARM_IMX8M_DDRC_DEVFREQ and imx-bus.o is over imx8m-ddrc.o. Need to edit the sequence.

Reordered kconfig to match. 8M_DDRC sorts before _BUS alphabetically but it's pettier this way, and matches tegra.

Quoted 24 lines
Quoted 24 lines
drivers/devfreq/Makefile +0 -0
  obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ)	+= imx8m-ddrc.o
  obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)	+= rk3399_dmc.o
  obj-$(CONFIG_ARM_TEGRA_DEVFREQ)		+= tegra30-devfreq.o
  obj-$(CONFIG_ARM_TEGRA20_DEVFREQ)	+= tegra20-devfreq.o
 
drivers/devfreq/imx-bus.c new file +13 -0
new file mode 100644
index 000000000000..285e0f1ae6b1
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <linux/clk.h>
+#include <linux/devfreq.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_opp.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
Quoted 8 lines

drivers/devfreq/imx-bus.c line 19

Quoted 6 lines
drivers/devfreq/imx-bus.c new file +6 -0
+
+struct imx_bus {
+	struct devfreq_dev_profile profile;
+	struct devfreq *devfreq;
+	struct clk *clk;
+	struct devfreq_passive_data passive_data;

This patch doesn't touch the passive_data.

dropped

Quoted 12 lines
Quoted 12 lines
drivers/devfreq/imx-bus.c new file +12 -0
+};
+
+static int imx_bus_target(struct device *dev,
+		unsigned long *freq, u32 flags)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+	struct dev_pm_opp *new_opp;
+	unsigned long new_freq;
+	int ret;
+
+	new_opp = devfreq_recommended_opp(dev, freq, flags);
+	if (IS_ERR(new_opp)) {
Quoted 8 lines

drivers/devfreq/imx-bus.c line 36

Quoted 5 lines
drivers/devfreq/imx-bus.c new file +5 -0
+		ret = PTR_ERR(new_opp);
+		dev_err(dev, "failed to get recommended opp: %d\n", ret);
+		return ret;
+	}
+	new_freq = dev_pm_opp_get_freq(new_opp);

It doesn't need. Because the new frequency is stored to 'freq' by calling devfreq_recommended_opp().

fixed

Quoted 5 lines

drivers/devfreq/imx-bus.c line 39

Quoted 3 lines
drivers/devfreq/imx-bus.c new file +3 -0
+	dev_pm_opp_put(new_opp);
+
+	return clk_set_rate(priv->clk, new_freq);

nitpick. you can use dev_pm_opp_set_rate(). But, I'm not forcing to use it.

Switched to dev_pm_opp_set_rate.

It might be interesting to add regulators control later, on some chips the main NOC can run at different voltages.

Quoted 37 lines
Quoted 37 lines
drivers/devfreq/imx-bus.c new file +36 -0
+}
+
+static int imx_bus_get_cur_freq(struct device *dev, unsigned long *freq)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+
+	*freq = clk_get_rate(priv->clk);
+
+	return 0;
+}
+
+static int imx_bus_get_dev_status(struct device *dev,
+		struct devfreq_dev_status *stat)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+
+	stat->busy_time = 0;
+	stat->total_time = 0;
+	stat->current_frequency = clk_get_rate(priv->clk);
+
+	return 0;
+}
+
+static void imx_bus_exit(struct device *dev)
+{
+	dev_pm_opp_of_remove_table(dev);
+}
+
+static int imx_bus_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct imx_bus *priv;
+	const char *gov = DEVFREQ_GOV_USERSPACE;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
Quoted 8 lines

drivers/devfreq/imx-bus.c line 80

Quoted 5 lines
drivers/devfreq/imx-bus.c new file +5 -0
+	if (!priv)
+		return -ENOMEM;
+
+	/*
+	 * Fetch the clock to adjust but don't explictly enable.

Need to fix typo.
s/explictly/explicitly

fixed

Quoted 65 lines
Quoted 63 lines
drivers/devfreq/imx-bus.c new file +62 -0
+	 *
+	 * For imx bus clock clk_set_rate is safe no matter if the clock is on
+	 * or off and some peripheral side-buses might be off unless enabled by
+	 * drivers for devices on those specific buses.
+	 *
+	 * Rate adjustment on a disabled bus clock just takes effect later.
+	 */
+	priv->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(priv->clk)) {
+		ret = PTR_ERR(priv->clk);
+		dev_err(dev, "failed to fetch clk: %d\n", ret);
+		return ret;
+	}
+	platform_set_drvdata(pdev, priv);
+
+	ret = dev_pm_opp_of_add_table(dev);
+	if (ret < 0) {
+		dev_err(dev, "failed to get OPP table\n");
+		return ret;
+	}
+
+	priv->profile.polling_ms = 1000;
+	priv->profile.target = imx_bus_target;
+	priv->profile.get_dev_status = imx_bus_get_dev_status;
+	priv->profile.exit = imx_bus_exit;
+	priv->profile.get_cur_freq = imx_bus_get_cur_freq;
+	priv->profile.initial_freq = clk_get_rate(priv->clk);
+
+	priv->devfreq = devm_devfreq_add_device(dev, &priv->profile,
+						gov, NULL);
+	if (IS_ERR(priv->devfreq)) {
+		ret = PTR_ERR(priv->devfreq);
+		dev_err(dev, "failed to add devfreq device: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	dev_pm_opp_of_remove_table(dev);
+	return ret;
+}
+
+static const struct of_device_id imx_bus_of_match[] = {
+	{ .compatible = "fsl,imx8m-noc", },
+	{ .compatible = "fsl,imx8m-nic", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_bus_of_match);
+
+static struct platform_driver imx_bus_platdrv = {
+	.probe		= imx_bus_probe,
+	.driver = {
+		.name	= "imx-bus-devfreq",
+		.of_match_table = of_match_ptr(imx_bus_of_match),
+	},
+};
+module_platform_driver(imx_bus_platdrv);
+
+MODULE_DESCRIPTION("Generic i.MX bus frequency scaling driver");
+MODULE_AUTHOR("Leonard Crestez <[email protected]>");
+MODULE_LICENSE("GPL v2");
maintainer
#6 lore raw

Re: [PATCH 2/8] PM / devfreq: Add generic imx bus scaling driver

Quoted 9 lines · Leonard Crestez
Quoted 4 lines · Chanwoo Choi

Hi,

Looks good to me. I added the comments.
But, it need to add the dt binding documentation for this device.

DT bindings were included:

https://patchwork.kernel.org/patch/11458981/

The dt-binding document for this driver is required under Documentation/devicetree/binding/devfreq.

It is difficult to catch where is the dt-binding document for this driver for who don't know the detailed history of this driver. I don't said that add the duplicate documentation But, at least the some document have to point out the reference.

Quoted 257 lines
Quoted 5 lines

The old email of Artur Świgoń is not used. On next time,
use following the new email address Because when I reply the mail, always show the fail message from thunderbird due to the Artur's old email. <[email protected]> -> <[email protected]>

Yeah, I received multiple bounces because of this.

Quoted 25 lines · Leonard Crestez
Quoted 24 lines

Add initial support for dynamic frequency switching on pieces of the imx interconnect fabric.

All this driver does is set a clk rate based on an opp table, it does not map register areas.

---
  drivers/devfreq/Kconfig   |   9 +++
  drivers/devfreq/Makefile  |   1 +
  drivers/devfreq/imx-bus.c | 142 ++++++++++++++++++++++++++++++++++++++
  3 files changed, 152 insertions(+)

create mode 100644 drivers/devfreq/imx-bus.c

drivers/devfreq/Kconfig +0 -0
index 0b1df12e0f21..44d26192ddc4 100644
@@ -99,10 +99,19 @@ config ARM_IMX8M_DDRC_DEVFREQ
  	select DEVFREQ_GOV_USERSPACE
  	help
  	  This adds the DEVFREQ driver for the i.MX8M DDR Controller. It allows
  	  adjusting DRAM frequency.
 
Quoted 8 lines

drivers/devfreq/Kconfig config ARM_IMX8M_DDRC_DEVFREQ · line 108

Quoted 5 lines
drivers/devfreq/Kconfig +5 -0
+config ARM_IMX_BUS_DEVFREQ
+	tristate "i.MX Generic Bus DEVFREQ Driver"
+	depends on ARCH_MXC || COMPILE_TEST
+	select DEVFREQ_GOV_PASSIVE
+	select DEVFREQ_GOV_USERSPACE

Maybe, you would update it by using passive governor? But, in this version, it doesn't handle the any passive governor.

dropped

Quoted 17 lines
Quoted 17 lines
drivers/devfreq/Kconfig +4 -0
+	help
+	  This adds the generic DEVFREQ driver for i.MX interconnects. It
+	  allows adjusting NIC/NOC frequency.
+
  config ARM_TEGRA_DEVFREQ
  	tristate "NVIDIA Tegra30/114/124/210 DEVFREQ Driver"
  	depends on ARCH_TEGRA_3x_SOC || ARCH_TEGRA_114_SOC || \
  		ARCH_TEGRA_132_SOC || ARCH_TEGRA_124_SOC || \
  		ARCH_TEGRA_210_SOC || \
drivers/devfreq/Makefile +0 -0
index 3eb4d5e6635c..3ca1ad0ecb97 100644
@@ -7,10 +7,11 @@ obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)	+= governor_powersave.o
  obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)	+= governor_userspace.o
  obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)	+= governor_passive.o
 
Quoted 6 lines

drivers/devfreq/Makefile obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o · line 12

Quoted 3 lines
drivers/devfreq/Makefile +1 -0
  # DEVFREQ Drivers
  obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)	+= exynos-bus.o
+obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ)	+= imx-bus.o

The ARM_IMX_BUS_DEVFREQ config is under ARM_IMX8M_DDRC_DEVFREQ and imx-bus.o is over imx8m-ddrc.o. Need to edit the sequence.

Reordered kconfig to match. 8M_DDRC sorts before _BUS alphabetically but it's pettier this way, and matches tegra.

Quoted 24 lines
Quoted 24 lines
drivers/devfreq/Makefile +0 -0
  obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ)	+= imx8m-ddrc.o
  obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)	+= rk3399_dmc.o
  obj-$(CONFIG_ARM_TEGRA_DEVFREQ)		+= tegra30-devfreq.o
  obj-$(CONFIG_ARM_TEGRA20_DEVFREQ)	+= tegra20-devfreq.o
 
drivers/devfreq/imx-bus.c new file +13 -0
new file mode 100644
index 000000000000..285e0f1ae6b1
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <linux/clk.h>
+#include <linux/devfreq.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_opp.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
Quoted 8 lines

drivers/devfreq/imx-bus.c line 19

Quoted 6 lines
drivers/devfreq/imx-bus.c new file +6 -0
+
+struct imx_bus {
+	struct devfreq_dev_profile profile;
+	struct devfreq *devfreq;
+	struct clk *clk;
+	struct devfreq_passive_data passive_data;

This patch doesn't touch the passive_data.

dropped

Quoted 12 lines
Quoted 12 lines
drivers/devfreq/imx-bus.c new file +12 -0
+};
+
+static int imx_bus_target(struct device *dev,
+		unsigned long *freq, u32 flags)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+	struct dev_pm_opp *new_opp;
+	unsigned long new_freq;
+	int ret;
+
+	new_opp = devfreq_recommended_opp(dev, freq, flags);
+	if (IS_ERR(new_opp)) {
Quoted 8 lines

drivers/devfreq/imx-bus.c line 36

Quoted 5 lines
drivers/devfreq/imx-bus.c new file +5 -0
+		ret = PTR_ERR(new_opp);
+		dev_err(dev, "failed to get recommended opp: %d\n", ret);
+		return ret;
+	}
+	new_freq = dev_pm_opp_get_freq(new_opp);

It doesn't need. Because the new frequency is stored to 'freq' by calling devfreq_recommended_opp().

fixed

Quoted 5 lines

drivers/devfreq/imx-bus.c line 39

Quoted 3 lines
drivers/devfreq/imx-bus.c new file +3 -0
+	dev_pm_opp_put(new_opp);
+
+	return clk_set_rate(priv->clk, new_freq);

nitpick. you can use dev_pm_opp_set_rate(). But, I'm not forcing to use it.

Switched to dev_pm_opp_set_rate.

It might be interesting to add regulators control later, on some chips the main NOC can run at different voltages.

Quoted 37 lines
Quoted 37 lines
drivers/devfreq/imx-bus.c new file +36 -0
+}
+
+static int imx_bus_get_cur_freq(struct device *dev, unsigned long *freq)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+
+	*freq = clk_get_rate(priv->clk);
+
+	return 0;
+}
+
+static int imx_bus_get_dev_status(struct device *dev,
+		struct devfreq_dev_status *stat)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+
+	stat->busy_time = 0;
+	stat->total_time = 0;
+	stat->current_frequency = clk_get_rate(priv->clk);
+
+	return 0;
+}
+
+static void imx_bus_exit(struct device *dev)
+{
+	dev_pm_opp_of_remove_table(dev);
+}
+
+static int imx_bus_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct imx_bus *priv;
+	const char *gov = DEVFREQ_GOV_USERSPACE;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
Quoted 8 lines

drivers/devfreq/imx-bus.c line 80

Quoted 5 lines
drivers/devfreq/imx-bus.c new file +5 -0
+	if (!priv)
+		return -ENOMEM;
+
+	/*
+	 * Fetch the clock to adjust but don't explictly enable.

Need to fix typo.
s/explictly/explicitly

fixed

Quoted 65 lines
Quoted 63 lines
drivers/devfreq/imx-bus.c new file +62 -0
+	 *
+	 * For imx bus clock clk_set_rate is safe no matter if the clock is on
+	 * or off and some peripheral side-buses might be off unless enabled by
+	 * drivers for devices on those specific buses.
+	 *
+	 * Rate adjustment on a disabled bus clock just takes effect later.
+	 */
+	priv->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(priv->clk)) {
+		ret = PTR_ERR(priv->clk);
+		dev_err(dev, "failed to fetch clk: %d\n", ret);
+		return ret;
+	}
+	platform_set_drvdata(pdev, priv);
+
+	ret = dev_pm_opp_of_add_table(dev);
+	if (ret < 0) {
+		dev_err(dev, "failed to get OPP table\n");
+		return ret;
+	}
+
+	priv->profile.polling_ms = 1000;
+	priv->profile.target = imx_bus_target;
+	priv->profile.get_dev_status = imx_bus_get_dev_status;
+	priv->profile.exit = imx_bus_exit;
+	priv->profile.get_cur_freq = imx_bus_get_cur_freq;
+	priv->profile.initial_freq = clk_get_rate(priv->clk);
+
+	priv->devfreq = devm_devfreq_add_device(dev, &priv->profile,
+						gov, NULL);
+	if (IS_ERR(priv->devfreq)) {
+		ret = PTR_ERR(priv->devfreq);
+		dev_err(dev, "failed to add devfreq device: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	dev_pm_opp_of_remove_table(dev);
+	return ret;
+}
+
+static const struct of_device_id imx_bus_of_match[] = {
+	{ .compatible = "fsl,imx8m-noc", },
+	{ .compatible = "fsl,imx8m-nic", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_bus_of_match);
+
+static struct platform_driver imx_bus_platdrv = {
+	.probe		= imx_bus_probe,
+	.driver = {
+		.name	= "imx-bus-devfreq",
+		.of_match_table = of_match_ptr(imx_bus_of_match),
+	},
+};
+module_platform_driver(imx_bus_platdrv);
+
+MODULE_DESCRIPTION("Generic i.MX bus frequency scaling driver");
+MODULE_AUTHOR("Leonard Crestez <[email protected]>");
+MODULE_LICENSE("GPL v2");
Signature · 3 lines
Best Regards,
Chanwoo Choi
Samsung Electronics
#7 lore raw

Re: [PATCH 2/8] PM / devfreq: Add generic imx bus scaling driver

Quoted 7 lines · Chanwoo Choi
Quoted 6 lines · Leonard Crestez
Quoted 4 lines · Chanwoo Choi

Hi,

Looks good to me. I added the comments.
But, it need to add the dt binding documentation for this device.

Quoted 6 lines
Quoted 3 lines

DT bindings were included:

https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fpatch%2F11458981%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7C7381d117a4d1468cd2c608d7d68ecfac%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637213781167514099&amp;sdata=Qu8x14cXnuxlwOT2SlUOf%2FLgCVWbnJRKA4TBjMIWQeA%3D&amp;reserved=0

The dt-binding document for this driver is required under Documentation/devicetree/binding/devfreq.

Bindings for imx8m-ddrc were at one point posted for devicetree/bindings/devfreq but Rob Herring suggested to move them under "memory-controller" instead and I expect same logic makes sense here. Link to previous discussion:

https://patchwork.kernel.org/patch/11221919/

DT bindings should try to describe "hardware" rather than "drivers" and an "interconnect" is a class of hardware while "devfreq" isn't.

Not only that but the main noc has properties parsed by interconnect driver.

Quoted 4 lines

It is difficult to catch where is the dt-binding document for this driver for who don't know the detailed history of this driver. I don't said that add the duplicate documentation But, at least the some document have to point out the reference.

What I usually do to find information about a device is grep for the compat string in the entire tree.

Quoted 258 lines
Quoted 256 lines
Quoted 4 lines

The old email of Artur Świgoń is not used. On next time,
use following the new email address Because when I reply the mail, always show the fail message from thunderbird due to the Artur's old email. <[email protected]> -> <[email protected]>

Yeah, I received multiple bounces because of this.

Quoted 25 lines · Leonard Crestez
Quoted 24 lines

Add initial support for dynamic frequency switching on pieces of the imx interconnect fabric.

All this driver does is set a clk rate based on an opp table, it does not map register areas.

---
   drivers/devfreq/Kconfig   |   9 +++
   drivers/devfreq/Makefile  |   1 +
   drivers/devfreq/imx-bus.c | 142 ++++++++++++++++++++++++++++++++++++++
   3 files changed, 152 insertions(+)

create mode 100644 drivers/devfreq/imx-bus.c

drivers/devfreq/Kconfig +0 -0
index 0b1df12e0f21..44d26192ddc4 100644
@@ -99,10 +99,19 @@ config ARM_IMX8M_DDRC_DEVFREQ
   	select DEVFREQ_GOV_USERSPACE
   	help
   	  This adds the DEVFREQ driver for the i.MX8M DDR Controller. It allows
   	  adjusting DRAM frequency.
 
Quoted 8 lines

drivers/devfreq/Kconfig config ARM_IMX8M_DDRC_DEVFREQ · line 108

Quoted 5 lines
drivers/devfreq/Kconfig +5 -0
+config ARM_IMX_BUS_DEVFREQ
+	tristate "i.MX Generic Bus DEVFREQ Driver"
+	depends on ARCH_MXC || COMPILE_TEST
+	select DEVFREQ_GOV_PASSIVE
+	select DEVFREQ_GOV_USERSPACE

Maybe, you would update it by using passive governor? But, in this version, it doesn't handle the any passive governor.

dropped

Quoted 17 lines
Quoted 17 lines
drivers/devfreq/Kconfig +4 -0
+	help
+	  This adds the generic DEVFREQ driver for i.MX interconnects. It
+	  allows adjusting NIC/NOC frequency.
+
   config ARM_TEGRA_DEVFREQ
   	tristate "NVIDIA Tegra30/114/124/210 DEVFREQ Driver"
   	depends on ARCH_TEGRA_3x_SOC || ARCH_TEGRA_114_SOC || \
   		ARCH_TEGRA_132_SOC || ARCH_TEGRA_124_SOC || \
   		ARCH_TEGRA_210_SOC || \
drivers/devfreq/Makefile +0 -0
index 3eb4d5e6635c..3ca1ad0ecb97 100644
@@ -7,10 +7,11 @@ obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)	+= governor_powersave.o
   obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)	+= governor_userspace.o
   obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)	+= governor_passive.o
 
Quoted 6 lines

drivers/devfreq/Makefile obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o · line 12

Quoted 3 lines
drivers/devfreq/Makefile +1 -0
   # DEVFREQ Drivers
   obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)	+= exynos-bus.o
+obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ)	+= imx-bus.o

The ARM_IMX_BUS_DEVFREQ config is under ARM_IMX8M_DDRC_DEVFREQ and imx-bus.o is over imx8m-ddrc.o. Need to edit the sequence.

Reordered kconfig to match. 8M_DDRC sorts before _BUS alphabetically but it's pettier this way, and matches tegra.

Quoted 24 lines
Quoted 24 lines
drivers/devfreq/Makefile +0 -0
   obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ)	+= imx8m-ddrc.o
   obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)	+= rk3399_dmc.o
   obj-$(CONFIG_ARM_TEGRA_DEVFREQ)		+= tegra30-devfreq.o
   obj-$(CONFIG_ARM_TEGRA20_DEVFREQ)	+= tegra20-devfreq.o
 
drivers/devfreq/imx-bus.c new file +13 -0
new file mode 100644
index 000000000000..285e0f1ae6b1
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <linux/clk.h>
+#include <linux/devfreq.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_opp.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
Quoted 8 lines

drivers/devfreq/imx-bus.c line 19

Quoted 6 lines
drivers/devfreq/imx-bus.c new file +6 -0
+
+struct imx_bus {
+	struct devfreq_dev_profile profile;
+	struct devfreq *devfreq;
+	struct clk *clk;
+	struct devfreq_passive_data passive_data;

This patch doesn't touch the passive_data.

dropped

Quoted 12 lines
Quoted 12 lines
drivers/devfreq/imx-bus.c new file +12 -0
+};
+
+static int imx_bus_target(struct device *dev,
+		unsigned long *freq, u32 flags)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+	struct dev_pm_opp *new_opp;
+	unsigned long new_freq;
+	int ret;
+
+	new_opp = devfreq_recommended_opp(dev, freq, flags);
+	if (IS_ERR(new_opp)) {
Quoted 8 lines

drivers/devfreq/imx-bus.c line 36

Quoted 5 lines
drivers/devfreq/imx-bus.c new file +5 -0
+		ret = PTR_ERR(new_opp);
+		dev_err(dev, "failed to get recommended opp: %d\n", ret);
+		return ret;
+	}
+	new_freq = dev_pm_opp_get_freq(new_opp);

It doesn't need. Because the new frequency is stored to 'freq' by calling devfreq_recommended_opp().

fixed

Quoted 5 lines

drivers/devfreq/imx-bus.c line 39

Quoted 3 lines
drivers/devfreq/imx-bus.c new file +3 -0
+	dev_pm_opp_put(new_opp);
+
+	return clk_set_rate(priv->clk, new_freq);

nitpick. you can use dev_pm_opp_set_rate(). But, I'm not forcing to use it.

Switched to dev_pm_opp_set_rate.

It might be interesting to add regulators control later, on some chips the main NOC can run at different voltages.

Quoted 37 lines
Quoted 37 lines
drivers/devfreq/imx-bus.c new file +36 -0
+}
+
+static int imx_bus_get_cur_freq(struct device *dev, unsigned long *freq)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+
+	*freq = clk_get_rate(priv->clk);
+
+	return 0;
+}
+
+static int imx_bus_get_dev_status(struct device *dev,
+		struct devfreq_dev_status *stat)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+
+	stat->busy_time = 0;
+	stat->total_time = 0;
+	stat->current_frequency = clk_get_rate(priv->clk);
+
+	return 0;
+}
+
+static void imx_bus_exit(struct device *dev)
+{
+	dev_pm_opp_of_remove_table(dev);
+}
+
+static int imx_bus_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct imx_bus *priv;
+	const char *gov = DEVFREQ_GOV_USERSPACE;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
Quoted 8 lines

drivers/devfreq/imx-bus.c line 80

Quoted 5 lines
drivers/devfreq/imx-bus.c new file +5 -0
+	if (!priv)
+		return -ENOMEM;
+
+	/*
+	 * Fetch the clock to adjust but don't explictly enable.

Need to fix typo.
s/explictly/explicitly

fixed

Quoted 65 lines
Quoted 63 lines
drivers/devfreq/imx-bus.c new file +62 -0
+	 *
+	 * For imx bus clock clk_set_rate is safe no matter if the clock is on
+	 * or off and some peripheral side-buses might be off unless enabled by
+	 * drivers for devices on those specific buses.
+	 *
+	 * Rate adjustment on a disabled bus clock just takes effect later.
+	 */
+	priv->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(priv->clk)) {
+		ret = PTR_ERR(priv->clk);
+		dev_err(dev, "failed to fetch clk: %d\n", ret);
+		return ret;
+	}
+	platform_set_drvdata(pdev, priv);
+
+	ret = dev_pm_opp_of_add_table(dev);
+	if (ret < 0) {
+		dev_err(dev, "failed to get OPP table\n");
+		return ret;
+	}
+
+	priv->profile.polling_ms = 1000;
+	priv->profile.target = imx_bus_target;
+	priv->profile.get_dev_status = imx_bus_get_dev_status;
+	priv->profile.exit = imx_bus_exit;
+	priv->profile.get_cur_freq = imx_bus_get_cur_freq;
+	priv->profile.initial_freq = clk_get_rate(priv->clk);
+
+	priv->devfreq = devm_devfreq_add_device(dev, &priv->profile,
+						gov, NULL);
+	if (IS_ERR(priv->devfreq)) {
+		ret = PTR_ERR(priv->devfreq);
+		dev_err(dev, "failed to add devfreq device: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	dev_pm_opp_of_remove_table(dev);
+	return ret;
+}
+
+static const struct of_device_id imx_bus_of_match[] = {
+	{ .compatible = "fsl,imx8m-noc", },
+	{ .compatible = "fsl,imx8m-nic", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_bus_of_match);
+
+static struct platform_driver imx_bus_platdrv = {
+	.probe		= imx_bus_probe,
+	.driver = {
+		.name	= "imx-bus-devfreq",
+		.of_match_table = of_match_ptr(imx_bus_of_match),
+	},
+};
+module_platform_driver(imx_bus_platdrv);
+
+MODULE_DESCRIPTION("Generic i.MX bus frequency scaling driver");
+MODULE_AUTHOR("Leonard Crestez <[email protected]>");
+MODULE_LICENSE("GPL v2");
maintainer
#8 lore raw

Re: [PATCH 2/8] PM / devfreq: Add generic imx bus scaling driver

Quoted 20 lines · Leonard Crestez
Quoted 7 lines · Chanwoo Choi
Quoted 6 lines · Leonard Crestez
Quoted 4 lines · Chanwoo Choi

Hi,

Looks good to me. I added the comments.
But, it need to add the dt binding documentation for this device.

Quoted 6 lines
Quoted 3 lines

DT bindings were included:

https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fpatch%2F11458981%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7C7381d117a4d1468cd2c608d7d68ecfac%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637213781167514099&amp;sdata=Qu8x14cXnuxlwOT2SlUOf%2FLgCVWbnJRKA4TBjMIWQeA%3D&amp;reserved=0

The dt-binding document for this driver is required under Documentation/devicetree/binding/devfreq.

Bindings for imx8m-ddrc were at one point posted for devicetree/bindings/devfreq but Rob Herring suggested to move them under "memory-controller" instead and I expect same logic makes sense here. Link to previous discussion:

Quoted 6 lines

https://patchwork.kernel.org/patch/11221919/

DT bindings should try to describe "hardware" rather than "drivers" and an "interconnect" is a class of hardware while "devfreq" isn't.

Not only that but the main noc has properties parsed by interconnect driver.

OK. Thanks for reply.

Quoted 270 lines
Quoted 5 lines

It is difficult to catch where is the dt-binding document for this driver for who don't know the detailed history of this driver. I don't said that add the duplicate documentation But, at least the some document have to point out the reference.

What I usually do to find information about a device is grep for the compat string in the entire tree.

Quoted 258 lines
Quoted 256 lines
Quoted 4 lines

The old email of Artur Świgoń is not used. On next time,
use following the new email address Because when I reply the mail, always show the fail message from thunderbird due to the Artur's old email. <[email protected]> -> <[email protected]>

Yeah, I received multiple bounces because of this.

Quoted 25 lines · Leonard Crestez
Quoted 24 lines

Add initial support for dynamic frequency switching on pieces of the imx interconnect fabric.

All this driver does is set a clk rate based on an opp table, it does not map register areas.

---
   drivers/devfreq/Kconfig   |   9 +++
   drivers/devfreq/Makefile  |   1 +
   drivers/devfreq/imx-bus.c | 142 ++++++++++++++++++++++++++++++++++++++
   3 files changed, 152 insertions(+)

create mode 100644 drivers/devfreq/imx-bus.c

drivers/devfreq/Kconfig +0 -0
index 0b1df12e0f21..44d26192ddc4 100644
@@ -99,10 +99,19 @@ config ARM_IMX8M_DDRC_DEVFREQ
   	select DEVFREQ_GOV_USERSPACE
   	help
   	  This adds the DEVFREQ driver for the i.MX8M DDR Controller. It allows
   	  adjusting DRAM frequency.
 
Quoted 8 lines

drivers/devfreq/Kconfig config ARM_IMX8M_DDRC_DEVFREQ · line 108

Quoted 5 lines
drivers/devfreq/Kconfig +5 -0
+config ARM_IMX_BUS_DEVFREQ
+	tristate "i.MX Generic Bus DEVFREQ Driver"
+	depends on ARCH_MXC || COMPILE_TEST
+	select DEVFREQ_GOV_PASSIVE
+	select DEVFREQ_GOV_USERSPACE

Maybe, you would update it by using passive governor? But, in this version, it doesn't handle the any passive governor.

dropped

Quoted 17 lines
Quoted 17 lines
drivers/devfreq/Kconfig +4 -0
+	help
+	  This adds the generic DEVFREQ driver for i.MX interconnects. It
+	  allows adjusting NIC/NOC frequency.
+
   config ARM_TEGRA_DEVFREQ
   	tristate "NVIDIA Tegra30/114/124/210 DEVFREQ Driver"
   	depends on ARCH_TEGRA_3x_SOC || ARCH_TEGRA_114_SOC || \
   		ARCH_TEGRA_132_SOC || ARCH_TEGRA_124_SOC || \
   		ARCH_TEGRA_210_SOC || \
drivers/devfreq/Makefile +0 -0
index 3eb4d5e6635c..3ca1ad0ecb97 100644
@@ -7,10 +7,11 @@ obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)	+= governor_powersave.o
   obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)	+= governor_userspace.o
   obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)	+= governor_passive.o
 
Quoted 6 lines

drivers/devfreq/Makefile obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o · line 12

Quoted 3 lines
drivers/devfreq/Makefile +1 -0
   # DEVFREQ Drivers
   obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)	+= exynos-bus.o
+obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ)	+= imx-bus.o

The ARM_IMX_BUS_DEVFREQ config is under ARM_IMX8M_DDRC_DEVFREQ and imx-bus.o is over imx8m-ddrc.o. Need to edit the sequence.

Reordered kconfig to match. 8M_DDRC sorts before _BUS alphabetically but it's pettier this way, and matches tegra.

Quoted 24 lines
Quoted 24 lines
drivers/devfreq/Makefile +0 -0
   obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ)	+= imx8m-ddrc.o
   obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)	+= rk3399_dmc.o
   obj-$(CONFIG_ARM_TEGRA_DEVFREQ)		+= tegra30-devfreq.o
   obj-$(CONFIG_ARM_TEGRA20_DEVFREQ)	+= tegra20-devfreq.o
 
drivers/devfreq/imx-bus.c new file +13 -0
new file mode 100644
index 000000000000..285e0f1ae6b1
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <linux/clk.h>
+#include <linux/devfreq.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_opp.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
Quoted 8 lines

drivers/devfreq/imx-bus.c line 19

Quoted 6 lines
drivers/devfreq/imx-bus.c new file +6 -0
+
+struct imx_bus {
+	struct devfreq_dev_profile profile;
+	struct devfreq *devfreq;
+	struct clk *clk;
+	struct devfreq_passive_data passive_data;

This patch doesn't touch the passive_data.

dropped

Quoted 12 lines
Quoted 12 lines
drivers/devfreq/imx-bus.c new file +12 -0
+};
+
+static int imx_bus_target(struct device *dev,
+		unsigned long *freq, u32 flags)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+	struct dev_pm_opp *new_opp;
+	unsigned long new_freq;
+	int ret;
+
+	new_opp = devfreq_recommended_opp(dev, freq, flags);
+	if (IS_ERR(new_opp)) {
Quoted 8 lines

drivers/devfreq/imx-bus.c line 36

Quoted 5 lines
drivers/devfreq/imx-bus.c new file +5 -0
+		ret = PTR_ERR(new_opp);
+		dev_err(dev, "failed to get recommended opp: %d\n", ret);
+		return ret;
+	}
+	new_freq = dev_pm_opp_get_freq(new_opp);

It doesn't need. Because the new frequency is stored to 'freq' by calling devfreq_recommended_opp().

fixed

Quoted 5 lines

drivers/devfreq/imx-bus.c line 39

Quoted 3 lines
drivers/devfreq/imx-bus.c new file +3 -0
+	dev_pm_opp_put(new_opp);
+
+	return clk_set_rate(priv->clk, new_freq);

nitpick. you can use dev_pm_opp_set_rate(). But, I'm not forcing to use it.

Switched to dev_pm_opp_set_rate.

It might be interesting to add regulators control later, on some chips the main NOC can run at different voltages.

Quoted 37 lines
Quoted 37 lines
drivers/devfreq/imx-bus.c new file +36 -0
+}
+
+static int imx_bus_get_cur_freq(struct device *dev, unsigned long *freq)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+
+	*freq = clk_get_rate(priv->clk);
+
+	return 0;
+}
+
+static int imx_bus_get_dev_status(struct device *dev,
+		struct devfreq_dev_status *stat)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+
+	stat->busy_time = 0;
+	stat->total_time = 0;
+	stat->current_frequency = clk_get_rate(priv->clk);
+
+	return 0;
+}
+
+static void imx_bus_exit(struct device *dev)
+{
+	dev_pm_opp_of_remove_table(dev);
+}
+
+static int imx_bus_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct imx_bus *priv;
+	const char *gov = DEVFREQ_GOV_USERSPACE;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
Quoted 8 lines

drivers/devfreq/imx-bus.c line 80

Quoted 5 lines
drivers/devfreq/imx-bus.c new file +5 -0
+	if (!priv)
+		return -ENOMEM;
+
+	/*
+	 * Fetch the clock to adjust but don't explictly enable.

Need to fix typo.
s/explictly/explicitly

fixed

Quoted 65 lines
Quoted 63 lines
drivers/devfreq/imx-bus.c new file +62 -0
+	 *
+	 * For imx bus clock clk_set_rate is safe no matter if the clock is on
+	 * or off and some peripheral side-buses might be off unless enabled by
+	 * drivers for devices on those specific buses.
+	 *
+	 * Rate adjustment on a disabled bus clock just takes effect later.
+	 */
+	priv->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(priv->clk)) {
+		ret = PTR_ERR(priv->clk);
+		dev_err(dev, "failed to fetch clk: %d\n", ret);
+		return ret;
+	}
+	platform_set_drvdata(pdev, priv);
+
+	ret = dev_pm_opp_of_add_table(dev);
+	if (ret < 0) {
+		dev_err(dev, "failed to get OPP table\n");
+		return ret;
+	}
+
+	priv->profile.polling_ms = 1000;
+	priv->profile.target = imx_bus_target;
+	priv->profile.get_dev_status = imx_bus_get_dev_status;
+	priv->profile.exit = imx_bus_exit;
+	priv->profile.get_cur_freq = imx_bus_get_cur_freq;
+	priv->profile.initial_freq = clk_get_rate(priv->clk);
+
+	priv->devfreq = devm_devfreq_add_device(dev, &priv->profile,
+						gov, NULL);
+	if (IS_ERR(priv->devfreq)) {
+		ret = PTR_ERR(priv->devfreq);
+		dev_err(dev, "failed to add devfreq device: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	dev_pm_opp_of_remove_table(dev);
+	return ret;
+}
+
+static const struct of_device_id imx_bus_of_match[] = {
+	{ .compatible = "fsl,imx8m-noc", },
+	{ .compatible = "fsl,imx8m-nic", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_bus_of_match);
+
+static struct platform_driver imx_bus_platdrv = {
+	.probe		= imx_bus_probe,
+	.driver = {
+		.name	= "imx-bus-devfreq",
+		.of_match_table = of_match_ptr(imx_bus_of_match),
+	},
+};
+module_platform_driver(imx_bus_platdrv);
+
+MODULE_DESCRIPTION("Generic i.MX bus frequency scaling driver");
+MODULE_AUTHOR("Leonard Crestez <[email protected]>");
+MODULE_LICENSE("GPL v2");
Signature · 3 lines
Best Regards,
Chanwoo Choi
Samsung Electronics
#9 lore raw

PATCH 3/8 PM / devfreq: imx: Register interconnect device

In reply to Leonard Crestez

There is no single device which can represent the imx interconnect. Instead of adding a virtual one just make the main &noc act as the global interconnect provider.

The imx interconnect provider driver will scale the NOC and DDRC based on bandwidth request. More scalable nodes can be added in the future, for example for audio/display/vpu/gpu NICs.

---
 drivers/devfreq/imx-bus.c | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)
drivers/devfreq/imx-bus.c +39 -0
index 285e0f1ae6b1..e9b13e43bf0a 100644
@@ -15,10 +15,11 @@
 struct imx_bus {
 	struct devfreq_dev_profile profile;
 	struct devfreq *devfreq;
 	struct clk *clk;
 	struct devfreq_passive_data passive_data;
+	struct platform_device *icc_pdev;
 };
 
 static int imx_bus_target(struct device *dev,
 		unsigned long *freq, u32 flags)
 {
@@ -60,11 +61,42 @@ static int imx_bus_get_dev_status(struct device *dev,
 	return 0;
 }
 
 static void imx_bus_exit(struct device *dev)
 {
+	struct imx_bus *priv = dev_get_drvdata(dev);
+
 	dev_pm_opp_of_remove_table(dev);
+	platform_device_unregister(priv->icc_pdev);
+}
+
+/* imx_bus_init_icc() - register matching icc provider if required */
+static int imx_bus_init_icc(struct device *dev)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+	const char *icc_driver_name;
+
+	if (!of_get_property(dev->of_node, "#interconnect-cells", 0))
+		return 0;
+	if (!IS_ENABLED(CONFIG_INTERCONNECT_IMX)) {
+		dev_warn(dev, "imx interconnect drivers disabled\n");
+		return 0;
+	}
+
+	icc_driver_name = of_device_get_match_data(dev);
+	if (!icc_driver_name)
+		return 0;
+
+	priv->icc_pdev = platform_device_register_data(
+			dev, icc_driver_name, -1, NULL, 0);
+	if (IS_ERR(priv->icc_pdev)) {
+		dev_err(dev, "failed to register icc provider %s: %ld\n",
+				icc_driver_name, PTR_ERR(priv->devfreq));
+		return PTR_ERR(priv->devfreq);
+	}
+
+	return 0;
 }
 
 static int imx_bus_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -112,18 +144,25 @@ static int imx_bus_probe(struct platform_device *pdev)
 		ret = PTR_ERR(priv->devfreq);
 		dev_err(dev, "failed to add devfreq device: %d\n", ret);
 		goto err;
 	}
 
+	ret = imx_bus_init_icc(dev);
+	if (ret)
+		goto err;
+
 	return 0;
 
 err:
 	dev_pm_opp_of_remove_table(dev);
 	return ret;
 }
 
 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,imx8m-noc", },
 	{ .compatible = "fsl,imx8m-nic", },
 	{ /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, imx_bus_of_match);
Signature · 1 line
2.17.1
maintainer
#10 lore raw

Re: [PATCH 3/8] PM / devfreq: imx: Register interconnect device

Hi Leonard,

Quoted 32 lines · Leonard Crestez

There is no single device which can represent the imx interconnect. Instead of adding a virtual one just make the main &noc act as the global interconnect provider.

The imx interconnect provider driver will scale the NOC and DDRC based on bandwidth request. More scalable nodes can be added in the future, for example for audio/display/vpu/gpu NICs.

---
 drivers/devfreq/imx-bus.c | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)
drivers/devfreq/imx-bus.c +1 -0
index 285e0f1ae6b1..e9b13e43bf0a 100644
@@ -15,10 +15,11 @@
 struct imx_bus {
 	struct devfreq_dev_profile profile;
 	struct devfreq *devfreq;
 	struct clk *clk;
 	struct devfreq_passive_data passive_data;
+	struct platform_device *icc_pdev;
 };
 
 static int imx_bus_target(struct device *dev,
 		unsigned long *freq, u32 flags)
 {
@@ -60,11 +61,42 @@ static int imx_bus_get_dev_status(struct device *dev,
 	return 0;
 }

drivers/devfreq/imx-bus.c static int imx_bus_get_dev_status(struct device *dev, · line 72

Quoted 10 lines
drivers/devfreq/imx-bus.c +6 -0
 
 static void imx_bus_exit(struct device *dev)
 {
+	struct imx_bus *priv = dev_get_drvdata(dev);
+
 	dev_pm_opp_of_remove_table(dev);
+	platform_device_unregister(priv->icc_pdev);
+}
+
+/* imx_bus_init_icc() - register matching icc provider if required */

Better to add following comments without 'imx_bus_init_icc() -' comment. /* Register matching icc provider if required */

Quoted 5 lines
drivers/devfreq/imx-bus.c +5 -0
+static int imx_bus_init_icc(struct device *dev)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+	const char *icc_driver_name;
+

drivers/devfreq/imx-bus.c static int imx_bus_get_dev_status(struct device *dev, · line 87

Quoted 10 lines
drivers/devfreq/imx-bus.c +10 -0
+	if (!of_get_property(dev->of_node, "#interconnect-cells", 0))
+		return 0;
+	if (!IS_ENABLED(CONFIG_INTERCONNECT_IMX)) {
+		dev_warn(dev, "imx interconnect drivers disabled\n");
+		return 0;
+	}
+
+	icc_driver_name = of_device_get_match_data(dev);
+	if (!icc_driver_name)
+		return 0;

Recommend to add the error or warning message.

Quoted 16 lines
drivers/devfreq/imx-bus.c +10 -0
+
+	priv->icc_pdev = platform_device_register_data(
+			dev, icc_driver_name, -1, NULL, 0);
+	if (IS_ERR(priv->icc_pdev)) {
+		dev_err(dev, "failed to register icc provider %s: %ld\n",
+				icc_driver_name, PTR_ERR(priv->devfreq));
+		return PTR_ERR(priv->devfreq);
+	}
+
+	return 0;
 }
 
 static int imx_bus_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;

drivers/devfreq/imx-bus.c static int imx_bus_probe(struct platform_device *pdev) · line 150

Quoted 7 lines
drivers/devfreq/imx-bus.c +2 -0
@@ -112,18 +144,25 @@ static int imx_bus_probe(struct platform_device *pdev)
 		ret = PTR_ERR(priv->devfreq);
 		dev_err(dev, "failed to add devfreq device: %d\n", ret);
 		goto err;
 	}
 
+	ret = imx_bus_init_icc(dev);
+	if (ret)

Recommend to add the error message.

Quoted 19 lines
drivers/devfreq/imx-bus.c +5 -0
+		goto err;
+
 	return 0;
 
 err:
 	dev_pm_opp_of_remove_table(dev);
 	return ret;
 }
 
 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,imx8m-noc", },
 	{ .compatible = "fsl,imx8m-nic", },
 	{ /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, imx_bus_of_match);
Signature · 3 lines
Best Regards,
Chanwoo Choi
Samsung Electronics
#11 lore raw

Re: [PATCH 3/8] PM / devfreq: imx: Register interconnect device

Quoted 36 lines · Chanwoo Choi

Hi Leonard,

Quoted 33 lines · Leonard Crestez

There is no single device which can represent the imx interconnect. Instead of adding a virtual one just make the main &noc act as the global interconnect provider.

The imx interconnect provider driver will scale the NOC and DDRC based on bandwidth request. More scalable nodes can be added in the future, for example for audio/display/vpu/gpu NICs.

---
  drivers/devfreq/imx-bus.c | 39 +++++++++++++++++++++++++++++++++++++++
  1 file changed, 39 insertions(+)
drivers/devfreq/imx-bus.c +1 -0
index 285e0f1ae6b1..e9b13e43bf0a 100644
@@ -15,10 +15,11 @@
  struct imx_bus {
  	struct devfreq_dev_profile profile;
  	struct devfreq *devfreq;
  	struct clk *clk;
  	struct devfreq_passive_data passive_data;
+	struct platform_device *icc_pdev;
  };
 
  static int imx_bus_target(struct device *dev,
  		unsigned long *freq, u32 flags)
  {
@@ -60,11 +61,42 @@ static int imx_bus_get_dev_status(struct device *dev,
  	return 0;
  }
 
Quoted 12 lines

drivers/devfreq/imx-bus.c static int imx_bus_get_dev_status(struct device *dev, · line 72

Quoted 9 lines
drivers/devfreq/imx-bus.c +6 -0
  static void imx_bus_exit(struct device *dev)
  {
+	struct imx_bus *priv = dev_get_drvdata(dev);
+
  	dev_pm_opp_of_remove_table(dev);
+	platform_device_unregister(priv->icc_pdev);
+}
+
+/* imx_bus_init_icc() - register matching icc provider if required */

Better to add following comments without 'imx_bus_init_icc() -' comment. /* Register matching icc provider if required */

This form looks like standard kernel-doc

Quoted 9 lines
Quoted 9 lines
drivers/devfreq/imx-bus.c +9 -0
+static int imx_bus_init_icc(struct device *dev)
+{
+	struct imx_bus *priv = dev_get_drvdata(dev);
+	const char *icc_driver_name;
+
+	if (!of_get_property(dev->of_node, "#interconnect-cells", 0))
+		return 0;
+	if (!IS_ENABLED(CONFIG_INTERCONNECT_IMX)) {
+		dev_warn(dev, "imx interconnect drivers disabled\n");
Quoted 8 lines

drivers/devfreq/imx-bus.c static int imx_bus_get_dev_status(struct device *dev, · line 87

Quoted 6 lines
drivers/devfreq/imx-bus.c +6 -0
+		return 0;
+	}
+
+	icc_driver_name = of_device_get_match_data(dev);
+	if (!icc_driver_name)
+		return 0;

Recommend to add the error or warning message.

Makes sense, imx8m-nic shouldn't have #interconnect-cells so if this condition is reach an error should be printed.

Quoted 21 lines
Quoted 21 lines
drivers/devfreq/imx-bus.c +10 -0
+
+	priv->icc_pdev = platform_device_register_data(
+			dev, icc_driver_name, -1, NULL, 0);
+	if (IS_ERR(priv->icc_pdev)) {
+		dev_err(dev, "failed to register icc provider %s: %ld\n",
+				icc_driver_name, PTR_ERR(priv->devfreq));
+		return PTR_ERR(priv->devfreq);
+	}
+
+	return 0;
  }
 
  static int imx_bus_probe(struct platform_device *pdev)
  {
  	struct device *dev = &pdev->dev;
@@ -112,18 +144,25 @@ static int imx_bus_probe(struct platform_device *pdev)
  		ret = PTR_ERR(priv->devfreq);
  		dev_err(dev, "failed to add devfreq device: %d\n", ret);
  		goto err;
  	}
 
Quoted 4 lines

drivers/devfreq/imx-bus.c static int imx_bus_probe(struct platform_device *pdev) · line 150

Quoted 2 lines
drivers/devfreq/imx-bus.c +2 -0
+	ret = imx_bus_init_icc(dev);
+	if (ret)

Recommend to add the error message.

imx_bus_init_icc already prints errors. Printing again here would always result in a second message.

Quoted 9 lines
Quoted 9 lines
drivers/devfreq/imx-bus.c +2 -0
+		goto err;
+
  	return 0;
 
  err:
  	dev_pm_opp_of_remove_table(dev);
  	return ret;
  }
 
Quoted 10 lines

drivers/devfreq/imx-bus.c static int imx_bus_probe(struct platform_device *pdev) · line 168

Quoted 10 lines
drivers/devfreq/imx-bus.c +3 -0
  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,imx8m-noc", },
  	{ .compatible = "fsl,imx8m-nic", },
  	{ /* sentinel */ },
  };
  MODULE_DEVICE_TABLE(of, imx_bus_of_match);

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#12 lore raw

PATCH 4/8 interconnect: Add imx core driver

In reply to Leonard Crestez

This adds support for i.MX SoC family to interconnect framework.

Platform drivers can describe the interconnect graph and several adjustment knobs where icc node bandwidth is converted to a DEV_PM_QOS_MIN_FREQUENCY request.

The interconnect provider is probed through the main NOC device and other adjustable nodes on the same graph are found from a fsl,scalable-nodes phandle array property.

---
 drivers/interconnect/Kconfig      |   1 +
 drivers/interconnect/Makefile     |   1 +
 drivers/interconnect/imx/Kconfig  |   5 +
 drivers/interconnect/imx/Makefile |   3 +
 drivers/interconnect/imx/imx.c    | 298 ++++++++++++++++++++++++++++++
 drivers/interconnect/imx/imx.h    |  62 +++++++
 6 files changed, 370 insertions(+)
 create mode 100644 drivers/interconnect/imx/Kconfig
 create mode 100644 drivers/interconnect/imx/Makefile
 create mode 100644 drivers/interconnect/imx/imx.c
 create mode 100644 drivers/interconnect/imx/imx.h
drivers/interconnect/Kconfig +1 -0
index bfa4ca3ab7a9..e61802230f90 100644
@@ -10,7 +10,8 @@ menuconfig INTERCONNECT
 	  If unsure, say no.
 
 if INTERCONNECT
 
 source "drivers/interconnect/qcom/Kconfig"
+source "drivers/interconnect/imx/Kconfig"
 
 endif
drivers/interconnect/Makefile +1 -0
index 725029ae7a2c..6998288a7d98 100644
@@ -3,5 +3,6 @@
 CFLAGS_core.o				:= -I$(src)
 icc-core-objs				:= core.o
 
 obj-$(CONFIG_INTERCONNECT)		+= icc-core.o
 obj-$(CONFIG_INTERCONNECT_QCOM)		+= qcom/
+obj-$(CONFIG_INTERCONNECT_IMX)		+= imx/
drivers/interconnect/imx/Kconfig new file +5 -0
new file mode 100644
index 000000000000..f39336f8d603
@@ -0,0 +1,5 @@
+config INTERCONNECT_IMX
+	tristate "i.MX interconnect drivers"
+	depends on ARCH_MXC || COMPILE_TEST
+	help
+	  Generic interconnect drivers for i.MX SOCs
drivers/interconnect/imx/Makefile new file +3 -0
new file mode 100644
index 000000000000..86ae0bd28d8c
@@ -0,0 +1,3 @@
+imx-interconnect-objs			:= imx.o
+
+obj-$(CONFIG_INTERCONNECT_IMX)		+= imx-interconnect.o
drivers/interconnect/imx/imx.c new file +298 -0

298 lines not on this page · raw message

drivers/interconnect/imx/imx.h new file +62 -0

62 lines not on this page · raw message

Signature · 1 line
2.17.1
#13 lore raw

PATCH 5/8 interconnect: imx: Add platform driver for imx8mm

In reply to Leonard Crestez

Add a platform driver for the i.MX8MM SoC describing bus topology.

Bandwidth adjustments is currently only supported on the DDRC and main NOC. Scaling for the vpu/gpu/display NICs could be added in the future.

---
 drivers/interconnect/imx/Kconfig          |   4 +
 drivers/interconnect/imx/Makefile         |   2 +
 drivers/interconnect/imx/imx8mm.c         | 108 ++++++++++++++++++++++
 include/dt-bindings/interconnect/imx8mm.h |  49 ++++++++++
 4 files changed, 163 insertions(+)
 create mode 100644 drivers/interconnect/imx/imx8mm.c
 create mode 100644 include/dt-bindings/interconnect/imx8mm.h
drivers/interconnect/imx/Kconfig +4 -0
index f39336f8d603..2cd4fad4976a 100644
@@ -1,5 +1,9 @@
 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
drivers/interconnect/imx/Makefile +2 -0
index 86ae0bd28d8c..c234e5d3dfd1 100644
@@ -1,3 +1,5 @@
 imx-interconnect-objs			:= imx.o
+imx8mm-interconnect-objs       		:= imx8mm.o
 
 obj-$(CONFIG_INTERCONNECT_IMX)		+= imx-interconnect.o
+obj-$(CONFIG_INTERCONNECT_IMX8MM)	+= imx8mm-interconnect.o
drivers/interconnect/imx/imx8mm.c new file +108 -0

108 lines not on this page · raw message

include/dt-bindings/interconnect/imx8mm.h new file +49 -0

49 lines not on this page · raw message

Signature · 1 line
2.17.1
#14 lore raw

PATCH 6/8 interconnect: imx: Add platform driver for imx8mq

In reply to Leonard Crestez

Add a platform driver for the i.MX8MQ SoC describing bus topology, based on internal documentation.

---
 drivers/interconnect/imx/Kconfig          |   4 +
 drivers/interconnect/imx/Makefile         |   2 +
 drivers/interconnect/imx/imx8mq.c         | 106 ++++++++++++++++++++++
 include/dt-bindings/interconnect/imx8mq.h |  48 ++++++++++
 4 files changed, 160 insertions(+)
 create mode 100644 drivers/interconnect/imx/imx8mq.c
 create mode 100644 include/dt-bindings/interconnect/imx8mq.h
drivers/interconnect/imx/Kconfig +4 -0
index 2cd4fad4976a..a2e6127f25b7 100644
@@ -5,5 +5,9 @@ config INTERCONNECT_IMX
 	  Generic interconnect drivers for i.MX SOCs
 
 config INTERCONNECT_IMX8MM
 	tristate "i.MX8MM interconnect driver"
 	depends on INTERCONNECT_IMX
+
+config INTERCONNECT_IMX8MQ
+	tristate "i.MX8MQ interconnect driver"
+	depends on INTERCONNECT_IMX
drivers/interconnect/imx/Makefile +2 -0
index c234e5d3dfd1..e7d7e029d6c7 100644
@@ -1,5 +1,7 @@
 imx-interconnect-objs			:= imx.o
 imx8mm-interconnect-objs       		:= imx8mm.o
+imx8mq-interconnect-objs       		:= imx8mq.o
 
 obj-$(CONFIG_INTERCONNECT_IMX)		+= imx-interconnect.o
 obj-$(CONFIG_INTERCONNECT_IMX8MM)	+= imx8mm-interconnect.o
+obj-$(CONFIG_INTERCONNECT_IMX8MQ)	+= imx8mq-interconnect.o
drivers/interconnect/imx/imx8mq.c new file +106 -0

106 lines not on this page · raw message

include/dt-bindings/interconnect/imx8mq.h new file +48 -0

48 lines not on this page · raw message

Signature · 1 line
2.17.1
#15 lore raw

PATCH 7/8 interconnect: imx: Add platform driver for imx8mn

In reply to Leonard Crestez

Add a platform driver for the i.MX8MN SoC describing bus topology, based on internal documentation.

---
 drivers/interconnect/imx/Kconfig          |  4 +
 drivers/interconnect/imx/Makefile         |  2 +
 drivers/interconnect/imx/imx8mn.c         | 97 +++++++++++++++++++++++
 include/dt-bindings/interconnect/imx8mn.h | 41 ++++++++++
 4 files changed, 144 insertions(+)
 create mode 100644 drivers/interconnect/imx/imx8mn.c
 create mode 100644 include/dt-bindings/interconnect/imx8mn.h
drivers/interconnect/imx/Kconfig +4 -0
index a2e6127f25b7..be2928362bb7 100644
@@ -6,8 +6,12 @@ config INTERCONNECT_IMX
 
 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
drivers/interconnect/imx/Makefile +2 -0
index e7d7e029d6c7..21fd5233754f 100644
@@ -1,7 +1,9 @@
 imx-interconnect-objs			:= imx.o
 imx8mm-interconnect-objs       		:= imx8mm.o
 imx8mq-interconnect-objs       		:= imx8mq.o
+imx8mn-interconnect-objs       		:= imx8mn.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
drivers/interconnect/imx/imx8mn.c new file +97 -0

97 lines not on this page · raw message

include/dt-bindings/interconnect/imx8mn.h new file +41 -0

41 lines not on this page · raw message

Signature · 1 line
2.17.1
#16 lore raw

PATCH 8/8 arm64: dts: imx8m: Add NOC nodes

In reply to Leonard Crestez

Add nodes for the main interconnect of the imx8m series chips.

These nodes are bound to by devfreq and interconnect drivers.

---
 arch/arm64/boot/dts/freescale/imx8mm.dtsi | 24 +++++++++++++++++++++++
 arch/arm64/boot/dts/freescale/imx8mn.dtsi | 24 +++++++++++++++++++++++
 arch/arm64/boot/dts/freescale/imx8mq.dtsi | 24 +++++++++++++++++++++++
 3 files changed, 72 insertions(+)
arch/arm64/boot/dts/freescale/imx8mm.dtsi +24 -0
index 175c28ae10cf..41047b6709b6 100644
@@ -6,10 +6,11 @@
 #include <dt-bindings/clock/imx8mm-clock.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/interconnect/imx8mm.h>
 
 #include "imx8mm-pinfunc.h"
 
 / {
 	interrupt-parent = <&gic>;
@@ -860,10 +861,33 @@
 				status = "disabled";
 			};
 
 		};
 
+		noc: interconnect@32700000 {
+			compatible = "fsl,imx8mm-noc", "fsl,imx8m-noc";
+			reg = <0x32700000 0x100000>;
+			clocks = <&clk IMX8MM_CLK_NOC>;
+			fsl,ddrc = <&ddrc>;
+			#interconnect-cells = <1>;
+			operating-points-v2 = <&noc_opp_table>;
+
+			noc_opp_table: opp-table {
+				compatible = "operating-points-v2";
+
+				opp-150M {
+					opp-hz = /bits/ 64 <150000000>;
+				};
+				opp-375M {
+					opp-hz = /bits/ 64 <375000000>;
+				};
+				opp-750M {
+					opp-hz = /bits/ 64 <750000000>;
+				};
+			};
+		};
+
 		aips4: bus@32c00000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			reg = <0x32df0000 0x10000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
arch/arm64/boot/dts/freescale/imx8mn.dtsi +24 -0
index 88e7d74e077f..e8a55956813f 100644
@@ -6,10 +6,11 @@
 #include <dt-bindings/clock/imx8mn-clock.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/interconnect/imx8mn.h>
 
 #include "imx8mn-pinfunc.h"
 
 / {
 	interrupt-parent = <&gic>;
@@ -751,10 +752,33 @@
 				status = "disabled";
 			};
 
 		};
 
+		noc: interconnect@32700000 {
+			compatible = "fsl,imx8mn-noc", "fsl,imx8m-noc";
+			reg = <0x32700000 0x100000>;
+			clocks = <&clk IMX8MN_CLK_NOC>;
+			fsl,ddrc = <&ddrc>;
+			#interconnect-cells = <1>;
+			operating-points-v2 = <&noc_opp_table>;
+
+			noc_opp_table: opp-table {
+				compatible = "operating-points-v2";
+
+				opp-100M {
+					opp-hz = /bits/ 64 <100000000>;
+				};
+				opp-600M {
+					opp-hz = /bits/ 64 <600000000>;
+				};
+				opp-800M {
+					opp-hz = /bits/ 64 <800000000>;
+				};
+			};
+		};
+
 		aips4: bus@32c00000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			reg = <0x32df0000 0x10000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
arch/arm64/boot/dts/freescale/imx8mq.dtsi +24 -0
index ea93bc4b7d7e..3a208feec74c 100644
@@ -9,10 +9,11 @@
 #include <dt-bindings/reset/imx8mq-reset.h>
 #include <dt-bindings/gpio/gpio.h>
 #include "dt-bindings/input/input.h"
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/interconnect/imx8mq.h>
 #include "imx8mq-pinfunc.h"
 
 / {
 	interrupt-parent = <&gpc>;
 
@@ -1026,10 +1027,33 @@
 				fsl,num-rx-queues = <3>;
 				status = "disabled";
 			};
 		};
 
+		noc: interconnect@32700000 {
+			compatible = "fsl,imx8mq-noc", "fsl,imx8m-noc";
+			reg = <0x32700000 0x100000>;
+			clocks = <&clk IMX8MQ_CLK_NOC>;
+			fsl,ddrc = <&ddrc>;
+			#interconnect-cells = <1>;
+			operating-points-v2 = <&noc_opp_table>;
+
+			noc_opp_table: opp-table {
+				compatible = "operating-points-v2";
+
+				opp-133M {
+					opp-hz = /bits/ 64 <133333333>;
+				};
+				opp-400M {
+					opp-hz = /bits/ 64 <400000000>;
+				};
+				opp-800M {
+					opp-hz = /bits/ 64 <800000000>;
+				};
+			};
+		};
+
 		bus@32c00000 { /* AIPS4 */
 			compatible = "fsl,aips-bus", "simple-bus";
 			reg = <0x32df0000 0x10000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
Signature · 1 line
2.17.1
#17 lore raw
In reply to Leonard Crestez
Quoted 26 lines · Leonard Crestez

This series adds interconnect scaling support for imx8m series chips. It uses a per-SOC interconnect provider layered on top of multiple instances of devfreq for scalable nodes along the interconnect.

Existing qcom interconnect providers mostly translate bandwidth requests into firmware calls but equivalent firmware on imx8m is much thinner. Scaling support for individual nodes is implemented as distinct devfreq drivers instead.

The imx interconnect provider doesn't communicate with devfreq directly but rather computes "minimum frequencies" for nodes along the path and creates dev_pm_qos requests.

Since there is no single devicetree node that can represent the "interconnect" the main NOC is picked as the "interconnect provider" and will probe the interconnect platform device if #interconnect-cells is present. This avoids introducing "virtual" devices but it means that DT bindings of main NOC includes properties for both devfreq and interconnect.

Only the ddrc and main noc are scalable right now but more can be added.

Also available on a github branch (with various unrelated changes):
https://github.com/cdleonard/linux/tree/next
Testing currently requires NXP branch of atf+uboot

Quoted 6 lines

Martin: I believe you should be able to use this to control DRAM frequency from video by just adding interconnect consumer code to nwl-dsi. Sample code:

	https://github.com/cdleonard/linux/commit/43772762aa5045f1ce5623740f9a4baef988d083
	https://github.com/cdleonard/linux/commit/7b601e981b1f517b5d98b43bde292972ded13086

Thanks for updating this series Leonard! A few questions for my understanding before trying to test:

Isn't the ddrc_opp_table missing in these additions to the DT? That's what I want to scale after all.

If I want to keep calling the "request", now icc_set_bw(), in nwl-dsi:
I'd add an "interconnects" property to the node, but what would be my interconnect master? i.e.: interconnects = <&noc master? &noc IMX8MQ_ICS_DRAM>; At least it's not obvious to me from interconnect/imx/imx8mq.c

the interconnect framework seems to be powerful indeed, but I still need to fully wrap my head around it.

thanks for the help so far,

martin

Quoted 92 lines

Changes since RFCv6:
* Replace scalable-nodes stuff with just a fsl,ddrc property. Future scalable nodes can be added as additional phandles on the NOC
* Allow building interconnect drivers as modules
* Handle icc_provider_del errors in imx_icc_unregister (like EBUSY).
* Rename imx-devfreq to imx-bus, similar to exynos-bus
* Explain why imx bus clock enabling is not required
* All dependencies accepted (some time ago).

Changes since RFCv5:
* Replace scanning for interconnect-node-id with explicit scalable-nodes/scalable-node-ids property on NoC.
* Now passes make dtbs_check
* Remove struct imx_icc_provider
* Switch to of_icc_xlate_onecell
* Use of_find_device_by_node to fetch QoS target, this causes fewer probe deferrals, removes dependency on devfreq API and even allows reloading ddrc module at runtime
* Add imx_icc_node_destroy helper
* Remove 0/1 on DEFINE_BUS_SLAVE/MASTER which created spurious links

Changes since RFCv4:
* Drop icc proxy nonsense
* Make devfreq driver for NOC probe the ICC driver if #interconnect-cells is present
* Move NOC support to interconnect series and rename the node in DT
* Add support for all chips at once, differences are not intereseting and there is more community interest for 8mq than 8mm.

Changes since RFCv3:
* Remove the virtual "icc" node and add devfreq nodes as proxy providers
* Fix build on 32-bit arm (reported by kbuilt test robot)
* Remove ARCH_MXC_ARM64 (never existed in upstream)
* Remove _numlinks, calculate instead
* Replace __BUSFREQ_H header guard
* Improve commit message and comment spelling
* Fix checkpatch issues
Link to RFCv3: https://patchwork.kernel.org/cover/11078671/

Changes since RFCv2 and initial work by Alexandre Bailon:
* Relying on devfreq and dev_pm_qos instead of CLK
* No more "platform opp" stuff
* No more special suspend handling: use suspend-opp on devfreq instead
* Replace all mentions of "busfreq" with "interconnect" Link to v2: https://patchwork.kernel.org/cover/11021563/

Leonard Crestez (8):
dt-bindings: interconnect: Add bindings for imx8m noc PM / devfreq: Add generic imx bus scaling driver PM / devfreq: imx: Register interconnect device
interconnect: Add imx core driver
interconnect: imx: Add platform driver for imx8mm
interconnect: imx: Add platform driver for imx8mq
interconnect: imx: Add platform driver for imx8mn
arm64: dts: imx8m: Add NOC nodes

 .../bindings/interconnect/fsl,imx8m-noc.yaml  | 138 ++++++++
 arch/arm64/boot/dts/freescale/imx8mm.dtsi     |  24 ++
 arch/arm64/boot/dts/freescale/imx8mn.dtsi     |  24 ++
 arch/arm64/boot/dts/freescale/imx8mq.dtsi     |  24 ++
 drivers/devfreq/Kconfig                       |   9 +
 drivers/devfreq/Makefile                      |   1 +
 drivers/devfreq/imx-bus.c                     | 181 +++++++++++
 drivers/interconnect/Kconfig                  |   1 +
 drivers/interconnect/Makefile                 |   1 +
 drivers/interconnect/imx/Kconfig              |  17 +
 drivers/interconnect/imx/Makefile             |   9 +
 drivers/interconnect/imx/imx.c                | 298 ++++++++++++++++++
 drivers/interconnect/imx/imx.h                |  62 ++++
 drivers/interconnect/imx/imx8mm.c             | 108 +++++++
 drivers/interconnect/imx/imx8mn.c             |  97 ++++++
 drivers/interconnect/imx/imx8mq.c             | 106 +++++++
 include/dt-bindings/interconnect/imx8mm.h     |  49 +++
 include/dt-bindings/interconnect/imx8mn.h     |  41 +++
 include/dt-bindings/interconnect/imx8mq.h     |  48 +++
 19 files changed, 1238 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml
 create mode 100644 drivers/devfreq/imx-bus.c
 create mode 100644 drivers/interconnect/imx/Kconfig
 create mode 100644 drivers/interconnect/imx/Makefile
 create mode 100644 drivers/interconnect/imx/imx.c
 create mode 100644 drivers/interconnect/imx/imx.h
 create mode 100644 drivers/interconnect/imx/imx8mm.c
 create mode 100644 drivers/interconnect/imx/imx8mn.c
 create mode 100644 drivers/interconnect/imx/imx8mq.c
 create mode 100644 include/dt-bindings/interconnect/imx8mm.h
 create mode 100644 include/dt-bindings/interconnect/imx8mn.h
 create mode 100644 include/dt-bindings/interconnect/imx8mq.h
#18 lore raw

Hi Martin,

Quoted 37 lines · Martin Kepplinger
Quoted 26 lines · Leonard Crestez

This series adds interconnect scaling support for imx8m series chips. It uses a per-SOC interconnect provider layered on top of multiple instances of devfreq for scalable nodes along the interconnect.

Existing qcom interconnect providers mostly translate bandwidth requests into firmware calls but equivalent firmware on imx8m is much thinner. Scaling support for individual nodes is implemented as distinct devfreq drivers instead.

The imx interconnect provider doesn't communicate with devfreq directly but rather computes "minimum frequencies" for nodes along the path and creates dev_pm_qos requests.

Since there is no single devicetree node that can represent the "interconnect" the main NOC is picked as the "interconnect provider" and will probe the interconnect platform device if #interconnect-cells is present. This avoids introducing "virtual" devices but it means that DT bindings of main NOC includes properties for both devfreq and interconnect.

Only the ddrc and main noc are scalable right now but more can be added.

Also available on a github branch (with various unrelated changes):
https://github.com/cdleonard/linux/tree/next
Testing currently requires NXP branch of atf+uboot

Quoted 6 lines

Martin: I believe you should be able to use this to control DRAM frequency from video by just adding interconnect consumer code to nwl-dsi. Sample code:

	https://github.com/cdleonard/linux/commit/43772762aa5045f1ce5623740f9a4baef988d083
	https://github.com/cdleonard/linux/commit/7b601e981b1f517b5d98b43bde292972ded13086

Thanks for updating this series Leonard! A few questions for my understanding before trying to test:

Quoted 8 lines

Isn't the ddrc_opp_table missing in these additions to the DT? That's what I want to scale after all.

If I want to keep calling the "request", now icc_set_bw(), in nwl-dsi:
I'd add an "interconnects" property to the node, but what would be my interconnect master? i.e.: interconnects = <&noc master? &noc IMX8MQ_ICS_DRAM>; At least it's not obvious to me from interconnect/imx/imx8mq.c

The NWL DSI host controller is fed by DCSS or mxsfb so any bandwidth requirements should (as far as I understand things) go into the display controller driver since that's what fetches from RAM. Cheers,
-- Guido

Quoted 107 lines

the interconnect framework seems to be powerful indeed, but I still need to fully wrap my head around it.

thanks for the help so far,

martin

Quoted 83 lines

Changes since RFCv6:
* Replace scalable-nodes stuff with just a fsl,ddrc property. Future scalable nodes can be added as additional phandles on the NOC
* Allow building interconnect drivers as modules
* Handle icc_provider_del errors in imx_icc_unregister (like EBUSY).
* Rename imx-devfreq to imx-bus, similar to exynos-bus
* Explain why imx bus clock enabling is not required
* All dependencies accepted (some time ago).

Changes since RFCv5:
* Replace scanning for interconnect-node-id with explicit scalable-nodes/scalable-node-ids property on NoC.
* Now passes make dtbs_check
* Remove struct imx_icc_provider
* Switch to of_icc_xlate_onecell
* Use of_find_device_by_node to fetch QoS target, this causes fewer probe deferrals, removes dependency on devfreq API and even allows reloading ddrc module at runtime
* Add imx_icc_node_destroy helper
* Remove 0/1 on DEFINE_BUS_SLAVE/MASTER which created spurious links

Changes since RFCv4:
* Drop icc proxy nonsense
* Make devfreq driver for NOC probe the ICC driver if #interconnect-cells is present
* Move NOC support to interconnect series and rename the node in DT
* Add support for all chips at once, differences are not intereseting and there is more community interest for 8mq than 8mm.

Changes since RFCv3:
* Remove the virtual "icc" node and add devfreq nodes as proxy providers
* Fix build on 32-bit arm (reported by kbuilt test robot)
* Remove ARCH_MXC_ARM64 (never existed in upstream)
* Remove _numlinks, calculate instead
* Replace __BUSFREQ_H header guard
* Improve commit message and comment spelling
* Fix checkpatch issues
Link to RFCv3: https://patchwork.kernel.org/cover/11078671/

Changes since RFCv2 and initial work by Alexandre Bailon:
* Relying on devfreq and dev_pm_qos instead of CLK
* No more "platform opp" stuff
* No more special suspend handling: use suspend-opp on devfreq instead
* Replace all mentions of "busfreq" with "interconnect" Link to v2: https://patchwork.kernel.org/cover/11021563/

Leonard Crestez (8):
dt-bindings: interconnect: Add bindings for imx8m noc PM / devfreq: Add generic imx bus scaling driver PM / devfreq: imx: Register interconnect device
interconnect: Add imx core driver
interconnect: imx: Add platform driver for imx8mm
interconnect: imx: Add platform driver for imx8mq
interconnect: imx: Add platform driver for imx8mn
arm64: dts: imx8m: Add NOC nodes

 .../bindings/interconnect/fsl,imx8m-noc.yaml  | 138 ++++++++
 arch/arm64/boot/dts/freescale/imx8mm.dtsi     |  24 ++
 arch/arm64/boot/dts/freescale/imx8mn.dtsi     |  24 ++
 arch/arm64/boot/dts/freescale/imx8mq.dtsi     |  24 ++
 drivers/devfreq/Kconfig                       |   9 +
 drivers/devfreq/Makefile                      |   1 +
 drivers/devfreq/imx-bus.c                     | 181 +++++++++++
 drivers/interconnect/Kconfig                  |   1 +
 drivers/interconnect/Makefile                 |   1 +
 drivers/interconnect/imx/Kconfig              |  17 +
 drivers/interconnect/imx/Makefile             |   9 +
 drivers/interconnect/imx/imx.c                | 298 ++++++++++++++++++
 drivers/interconnect/imx/imx.h                |  62 ++++
 drivers/interconnect/imx/imx8mm.c             | 108 +++++++
 drivers/interconnect/imx/imx8mn.c             |  97 ++++++
 drivers/interconnect/imx/imx8mq.c             | 106 +++++++
 include/dt-bindings/interconnect/imx8mm.h     |  49 +++
 include/dt-bindings/interconnect/imx8mn.h     |  41 +++
 include/dt-bindings/interconnect/imx8mq.h     |  48 +++
 19 files changed, 1238 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml
 create mode 100644 drivers/devfreq/imx-bus.c
 create mode 100644 drivers/interconnect/imx/Kconfig
 create mode 100644 drivers/interconnect/imx/Makefile
Quoted 9 lines
 create mode 100644 drivers/interconnect/imx/imx.c
 create mode 100644 drivers/interconnect/imx/imx.h
 create mode 100644 drivers/interconnect/imx/imx8mm.c
 create mode 100644 drivers/interconnect/imx/imx8mn.c
 create mode 100644 drivers/interconnect/imx/imx8mq.c
 create mode 100644 include/dt-bindings/interconnect/imx8mm.h
 create mode 100644 include/dt-bindings/interconnect/imx8mn.h
 create mode 100644 include/dt-bindings/interconnect/imx8mq.h

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#19 lore raw
Quoted 48 lines · Guido Günther

Hi Martin,

Quoted 37 lines · Martin Kepplinger
Quoted 26 lines · Leonard Crestez

This series adds interconnect scaling support for imx8m series chips. It uses a per-SOC interconnect provider layered on top of multiple instances of devfreq for scalable nodes along the interconnect.

Existing qcom interconnect providers mostly translate bandwidth requests into firmware calls but equivalent firmware on imx8m is much thinner. Scaling support for individual nodes is implemented as distinct devfreq drivers instead.

The imx interconnect provider doesn't communicate with devfreq directly but rather computes "minimum frequencies" for nodes along the path and creates dev_pm_qos requests.

Since there is no single devicetree node that can represent the "interconnect" the main NOC is picked as the "interconnect provider" and will probe the interconnect platform device if #interconnect-cells is present. This avoids introducing "virtual" devices but it means that DT bindings of main NOC includes properties for both devfreq and interconnect.

Only the ddrc and main noc are scalable right now but more can be added.

Also available on a github branch (with various unrelated changes):
https://github.com/cdleonard/linux/tree/next
Testing currently requires NXP branch of atf+uboot

Quoted 6 lines

Martin: I believe you should be able to use this to control DRAM frequency from video by just adding interconnect consumer code to nwl-dsi. Sample code:

	https://github.com/cdleonard/linux/commit/43772762aa5045f1ce5623740f9a4baef988d083
	https://github.com/cdleonard/linux/commit/7b601e981b1f517b5d98b43bde292972ded13086

Thanks for updating this series Leonard! A few questions for my understanding before trying to test:

Quoted 8 lines

Isn't the ddrc_opp_table missing in these additions to the DT? That's what I want to scale after all.

If I want to keep calling the "request", now icc_set_bw(), in nwl-dsi:
I'd add an "interconnects" property to the node, but what would be my interconnect master? i.e.: interconnects = <&noc master? &noc IMX8MQ_ICS_DRAM>; At least it's not obvious to me from interconnect/imx/imx8mq.c

Quoted 6 lines

The NWL DSI host controller is fed by DCSS or mxsfb so any bandwidth requirements should (as far as I understand things) go into the display controller driver since that's what fetches from RAM. Cheers,
-- Guido

Hi,

Thanks a lot Leonard and Guido! Here's the tree I'm running, which is your patches based on Linus' tree, with icc request in mxsfb:

https://source.puri.sm/martin.kepplinger/linux-next/commits/5.6-rc7/librem5__integration_devfreq1

The path from icc via pm_qos to devfreq does work (which is great) - however only after setting the minimum frequencies via a governor - I set the "powersave" governor.

After that, frequencies are both set to high / low correctly.

My impression was that I should be able to use the "passive" governor (a passive devfreq device?). What am I missing with using devfreq correctly? Or do I already?

other than the above uncertainty:

thanks so far!

martin

#20 lore raw
Quoted 37 lines · Martin Kepplinger
Quoted 36 lines · Guido Günther

Hi Martin,

Quoted 34 lines · Martin Kepplinger
Quoted 32 lines · Leonard Crestez

This series adds interconnect scaling support for imx8m series chips. It uses a per-SOC interconnect provider layered on top of multiple instances of devfreq for scalable nodes along the interconnect.

Existing qcom interconnect providers mostly translate bandwidth requests into firmware calls but equivalent firmware on imx8m is much thinner. Scaling support for individual nodes is implemented as distinct devfreq drivers instead.

The imx interconnect provider doesn't communicate with devfreq directly but rather computes "minimum frequencies" for nodes along the path and creates dev_pm_qos requests.

Since there is no single devicetree node that can represent the "interconnect" the main NOC is picked as the "interconnect provider" and will probe the interconnect platform device if #interconnect-cells is present. This avoids introducing "virtual" devices but it means that DT bindings of main NOC includes properties for both devfreq and interconnect.

Only the ddrc and main noc are scalable right now but more can be added.

Also available on a github branch (with various unrelated changes):

	https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fcdleonard%2Flinux%2Ftree%2Fnext&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7C52eb55181dce469eb85608d7d487bb93%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637211551737394247&amp;sdata=A0l5FBF%2BT3k7H5HMtRMfX8WfVSqQm9jijgr8aexCoUA%3D&amp;reserved=0

Testing currently requires NXP branch of atf+uboot

Martin: I believe you should be able to use this to control DRAM frequency from video by just adding interconnect consumer code to nwl-dsi. Sample code:

	https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fcdleonard%2Flinux%2Fcommit%2F43772762aa5045f1ce5623740f9a4baef988d083&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7C52eb55181dce469eb85608d7d487bb93%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637211551737394247&amp;sdata=%2B%2BGWQTaQLLk98yFRHJ0o3Sks9DHGuKv7twBvn89f1Tg%3D&amp;reserved=0
	https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fcdleonard%2Flinux%2Fcommit%2F7b601e981b1f517b5d98b43bde292972ded13086&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7C52eb55181dce469eb85608d7d487bb93%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637211551737394247&amp;sdata=Jy2%2FI3CE1H3ilmLvZAVhjlPHO3KRNK6%2F9dX%2BS124ROA%3D&amp;reserved=0
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

Thanks for updating this series Leonard! A few questions for my understanding before trying to test:

Isn't the ddrc_opp_table missing in these additions to the DT? That's what I want to scale after all.

DDRC OPP table belongs in board file because it can vary with RAM type on boards.

Quoted 11 lines
Quoted 11 lines
Quoted 5 lines

If I want to keep calling the "request", now icc_set_bw(), in nwl-dsi:
I'd add an "interconnects" property to the node, but what would be my interconnect master? i.e.: interconnects = <&noc master? &noc IMX8MQ_ICS_DRAM>; At least it's not obvious to me from interconnect/imx/imx8mq.c

The NWL DSI host controller is fed by DCSS or mxsfb so any bandwidth requirements should (as far as I understand things) go into the display controller driver since that's what fetches from RAM. Cheers,
-- Guido

This is correct.

Quoted 9 lines

Thanks a lot Leonard and Guido! Here's the tree I'm running, which is your patches based on Linus' tree, with icc request in mxsfb:

https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fsource.puri.sm%2Fmartin.kepplinger%2Flinux-next%2Fcommits%2F5.6-rc7%2Flibrem5__integration_devfreq1&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7C52eb55181dce469eb85608d7d487bb93%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637211551737394247&amp;sdata=FM8JoOuNa2gg09XVJ%2FLTLqK9rlL4hAwig2iM9cMYFhg%3D&amp;reserved=0

The path from icc via pm_qos to devfreq does work (which is great) - however only after setting the minimum frequencies via a governor - I set the "powersave" governor.

Quoted 5 lines

After that, frequencies are both set to high / low correctly.

My impression was that I should be able to use the "passive" governor (a passive devfreq device?). What am I missing with using devfreq correctly? Or do I already?

The devfreq governor is something else: it's used to make one devfreq device match frequencies with another devfreq device.

Setting the default governor to "powersave" is correct and roughly matches behavior in NXP kernel.

Quoted 1 line

Thanks!