Skip to contentSkip to conversation

interconnect: Add imx support via devfreq

RFC PATCH Superseded Leonard Crestez 3 participants 15 messages Oct 31, 2019 – Nov 12, 2019

Subsystems (4)

v5 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

v5 cover interconnect: Add imx support via devfreq

This series adds upstream DRAM and 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 (NIC/NOC and DDRC) is implemented through devfreq.

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

This needs core changes for dev_pm_qos frequency support for devfreq:

	https://patchwork.kernel.org/project/linux-arm-kernel/list/?series=196443

Since imx interconnect only needs to interact with imx devfreq it would also be possible to tie them together directly, but it would be a little sad.

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 is a bit odd.

On i.MX there are multiple instances of a few interconnect IPs, this patch identifies them by enumerating the entire devicetree scanning for the "interconnect-node-id" property. As far as I see current providers do this based entirely on compatible string of the interconnect instance and this seems very odd to me. Do you think we could move this "interconnect-node-id" approach to core interconnect bindings?

The same interconnect-node-id property is used to identify the DDRC and this is arguably a hack.

Also as a github branch (with few other changes):
https://github.com/cdleonard/linux/tree/next_imx_busfreq

This is layered upon imx-ddrc scaling support:
* https://patchwork.kernel.org/project/linux-arm-kernel/list/?series=196459
The DDRC only really interacts by receiving dev_pm_qos requests.

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/patch/11056789/

Leonard Crestez (10):
dt-bindings: devfreq: Add bindings for generic imx buses PM / devfreq: Add generic imx bus driver
PM / devfreq: imx: Register interconnect device PM / devfreq: Add devfreq_get_devfreq_by_node
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
arm64: dts: imx8m: Add interconnect provider properties

 .../devicetree/bindings/devfreq/imx.yaml      |  83 ++++++
 arch/arm64/boot/dts/freescale/imx8mm.dtsi     |  26 ++
 arch/arm64/boot/dts/freescale/imx8mn.dtsi     |  26 ++
 arch/arm64/boot/dts/freescale/imx8mq.dtsi     |  26 ++
 drivers/devfreq/Kconfig                       |  12 +
 drivers/devfreq/Makefile                      |   1 +
 drivers/devfreq/devfreq.c                     |  42 ++-
 drivers/devfreq/imx-devfreq.c                 | 185 ++++++++++++
 drivers/interconnect/Kconfig                  |   1 +
 drivers/interconnect/Makefile                 |   1 +
 drivers/interconnect/imx/Kconfig              |  17 ++
 drivers/interconnect/imx/Makefile             |   4 +
 drivers/interconnect/imx/imx.c                | 273 ++++++++++++++++++
 drivers/interconnect/imx/imx.h                |  60 ++++
 drivers/interconnect/imx/imx8mm.c             | 105 +++++++
 drivers/interconnect/imx/imx8mn.c             |  94 ++++++
 drivers/interconnect/imx/imx8mq.c             | 103 +++++++
 include/dt-bindings/interconnect/imx8mm.h     |  49 ++++
 include/dt-bindings/interconnect/imx8mn.h     |  41 +++
 include/dt-bindings/interconnect/imx8mq.h     |  48 +++
 include/linux/devfreq.h                       |   1 +
 21 files changed, 1187 insertions(+), 11 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/devfreq/imx.yaml
 create mode 100644 drivers/devfreq/imx-devfreq.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

RFC PATCH v5 1/10 dt-bindings: devfreq: Add bindings for generic imx buses

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.

Single node also acts as interconnect provider if #interconnect-cells is present.

---
 .../devicetree/bindings/devfreq/imx.yaml      | 83 +++++++++++++++++++
 1 file changed, 83 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/devfreq/imx.yaml
Documentation/devicetree/bindings/devfreq/imx.yaml new file +83 -0
new file mode 100644
index 000000000000..bfc825407764
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/devfreq/imx.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
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  operating-points-v2: true
+
+  devfreq:
+    description: |
+      Phandle to another devfreq device to match OPPs with by using the
+      passive governor.
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+
+  '#interconnect-cells':
+    description: |
+      If specified then also act as an interconnect provider. Should only be
+      set once per soc on main noc.
+    const: 1
+
+  interconnect-node-id:
+    description: |
+      i.MX chips have multiple scalable buses based on the same IP, this is
+      used to distinguish between. Uses same identifier namespace as consumer
+      "interconnects" property, for example one of the values in
+      "include/dt-bindings/interconnect/imx8mm.h"
+
+    const: 1
+
+required:
+  - compatible
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/imx8mm-clock.h>
+    noc: noc@32700000 {
+            compatible = "fsl,imx8mm-noc", "fsl,imx8m-noc";
+            reg = <0x32700000 0x100000>;
+            clocks = <&clk IMX8MM_CLK_NOC>;
+            operating-points-v2 = <&noc_opp_table>;
+    };
Signature · 1 line
2.17.1
maintainer
#2 lore raw

Re: [PATCH RFC v5 01/10] dt-bindings: devfreq: Add bindings for generic imx buses

Quoted 11 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.

Single node also acts as interconnect provider if #interconnect-cells is present.

---
 .../devicetree/bindings/devfreq/imx.yaml      | 83 +++++++++++++++++++

bindings/interconnect/

Quoted 9 lines
 1 file changed, 83 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/devfreq/imx.yaml
Documentation/devicetree/bindings/devfreq/imx.yaml new file +0 -0
new file mode 100644
index 000000000000..bfc825407764

Documentation/devicetree/bindings/devfreq/imx.yaml line 7

Quoted 7 lines
Documentation/devicetree/bindings/devfreq/imx.yaml new file +7 -0
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/devfreq/imx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic i.MX bus frequency device

i.MX8 specific?

Quoted 43 lines
Documentation/devicetree/bindings/devfreq/imx.yaml new file +43 -0
+
+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
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  operating-points-v2: true
+
+  devfreq:
+    description: |
+      Phandle to another devfreq device to match OPPs with by using the

Documentation/devicetree/bindings/devfreq/imx.yaml line 60

Quoted 10 lines
Documentation/devicetree/bindings/devfreq/imx.yaml new file +10 -0
+      passive governor.
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+
+  '#interconnect-cells':
+    description: |
+      If specified then also act as an interconnect provider. Should only be
+      set once per soc on main noc.
+    const: 1
+
+  interconnect-node-id:

Looks like common property, but it's not...

Generally, we don't do indexes or instance ids. So it needs a better explanation or drop this. The driver side looks like an odd marriage between interconnect and devfreq drivers that needs better integration, but I'm not all that familar with either.

Documentation/devicetree/bindings/devfreq/imx.yaml line 63

Quoted 3 lines
Documentation/devicetree/bindings/devfreq/imx.yaml new file +3 -0
+    description: |
+      i.MX chips have multiple scalable buses based on the same IP, this is
+      used to distinguish between. Uses same identifier namespace as consumer

It's not names, so number space? Just guessing because there's no type nor example.

Quoted 23 lines
Documentation/devicetree/bindings/devfreq/imx.yaml new file +20 -0
+      "interconnects" property, for example one of the values in
+      "include/dt-bindings/interconnect/imx8mm.h"
+
+    const: 1
+
+required:
+  - compatible
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/imx8mm-clock.h>
+    noc: noc@32700000 {
+            compatible = "fsl,imx8mm-noc", "fsl,imx8m-noc";
+            reg = <0x32700000 0x100000>;
+            clocks = <&clk IMX8MM_CLK_NOC>;
+            operating-points-v2 = <&noc_opp_table>;
+    };
Signature · 1 line
2.17.1
#3 lore raw

Re: [PATCH RFC v5 01/10] dt-bindings: devfreq: Add bindings for generic imx buses

Quoted 8 lines · Rob Herring
Quoted 7 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.

Single node also acts as interconnect provider if #interconnect-cells is present.

Quoted 6 lines
Quoted 4 lines
---
  .../devicetree/bindings/devfreq/imx.yaml      | 83 +++++++++++++++++++

bindings/interconnect/

Make sense. The only other two files in devicetree/bindings/devfreq are:
* rk3399_dmc: a memory controller
* exynos-bus: arguably an interconnect

Quoted 18 lines
Quoted 9 lines
  1 file changed, 83 insertions(+)

create mode 100644 Documentation/devicetree/bindings/devfreq/imx.yaml

Documentation/devicetree/bindings/devfreq/imx.yaml new file +0 -0
new file mode 100644
index 000000000000..bfc825407764

Documentation/devicetree/bindings/devfreq/imx.yaml line 7

Quoted 7 lines
Documentation/devicetree/bindings/devfreq/imx.yaml new file +7 -0
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fdevicetree.org%2Fschemas%2Fdevfreq%2Fimx.yaml%23&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7C95911400e0834b06269c08d761794cd2%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C1%7C637085045930647253&amp;sdata=88iAXoKObu%2FXBqZu6hNwnOUIffB8GxVLdGeBWiCjClI%3D&amp;reserved=0
+$schema: https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fdevicetree.org%2Fmeta-schemas%2Fcore.yaml%23&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7C95911400e0834b06269c08d761794cd2%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C1%7C637085045930647253&amp;sdata=0phpsG05ZsYc5SnI3FXZODJpJSEB2tzA5v02r7N%2BY2I%3D&amp;reserved=0
+
+title: Generic i.MX bus frequency device

i.MX8 specific?

Not really, but it's initially targeted at imx8m.

Quoted 55 lines
Quoted 42 lines
Documentation/devicetree/bindings/devfreq/imx.yaml new file +42 -0
+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
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  operating-points-v2: true
+
+  devfreq:
+    description: |
+      Phandle to another devfreq device to match OPPs with by using the

Documentation/devicetree/bindings/devfreq/imx.yaml line 60

Quoted 10 lines
Documentation/devicetree/bindings/devfreq/imx.yaml new file +10 -0
+      passive governor.
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+
+  '#interconnect-cells':
+    description: |
+      If specified then also act as an interconnect provider. Should only be
+      set once per soc on main noc.
+    const: 1
+
+  interconnect-node-id:

Looks like common property, but it's not...

Quoted 4 lines

Generally, we don't do indexes or instance ids. So it needs a better explanation or drop this. The driver side looks like an odd marriage between interconnect and devfreq drivers that needs better integration, but I'm not all that familar with either.

Current interconnect drivers all operate by sending messages via a mailbox to a system controller which handles bandwidth requests. They only perform request aggregation. On imx8m frequency scaling is also implemented in the kernel so the NOC becomes almost like a MFD.

The interconnect-node-id is used to find other scalable nodes for the same interconnect provider. I can replace this with a "scalable-nodes" array like this:

	noc: interconnect@32700000 {
		compatible = "fsl,imx8mq-noc", "fsl,imx8m-noc";
		reg = <0x32700000 0x100000>;
		clocks = <&clk IMX8MQ_CLK_NOC>;
		#interconnect-cells = <1>;
		fsl,scalable-node-ids = <IMX8MQ_ICN_NOC>,
					<IMX8MQ_ICS_DRAM>;
		fsl,scalable-nodes = <&noc>,
				     <&ddrc>;
		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>;
			};
		};
	};

	ddrc: dram-controller@3d400000 {
		compatible = "fsl,imx8mq-ddrc", "fsl,imx8m-ddrc";
		reg = <0x3d400000 0x400000>;
		clock-names = "core", "pll", "alt", "apb";
		clocks = <&clk IMX8MQ_CLK_DRAM_CORE>,
			 <&clk IMX8MQ_DRAM_PLL_OUT>,
			 <&clk IMX8MQ_CLK_DRAM_ALT>,
			 <&clk IMX8MQ_CLK_DRAM_APB>;
		devfreq-events = <&ddr_pmu>;
	};

It's a bit strange that the noc references itself but in advanced multiple NOC can be be present and there needs to be a way to map from the interconnect graph (node ids) to devicetree nodes.

Quoted 6 lines

Documentation/devicetree/bindings/devfreq/imx.yaml line 63

Quoted 3 lines
Documentation/devicetree/bindings/devfreq/imx.yaml new file +3 -0
+    description: |
+      i.MX chips have multiple scalable buses based on the same IP, this is
+      used to distinguish between. Uses same identifier namespace as consumer

It's not names, so number space? Just guessing because there's no type nor example.

Maybe "numeric namespace"?

Quoted 22 lines
Quoted 22 lines
Documentation/devicetree/bindings/devfreq/imx.yaml new file +20 -0
+      "interconnects" property, for example one of the values in
+      "include/dt-bindings/interconnect/imx8mm.h"
+
+    const: 1
+
+required:
+  - compatible
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/imx8mm-clock.h>
+    noc: noc@32700000 {
+            compatible = "fsl,imx8mm-noc", "fsl,imx8m-noc";
+            reg = <0x32700000 0x100000>;
+            clocks = <&clk IMX8MM_CLK_NOC>;
+            operating-points-v2 = <&noc_opp_table>;
+    };
Signature · 1 line
2.17.1
#4 lore raw

RFC PATCH v5 2/10 PM / devfreq: Add generic imx bus 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 even map registers.

---
 drivers/devfreq/Kconfig       |  12 +++
 drivers/devfreq/Makefile      |   1 +
 drivers/devfreq/imx-devfreq.c | 148 ++++++++++++++++++++++++++++++++++
 3 files changed, 161 insertions(+)
 create mode 100644 drivers/devfreq/imx-devfreq.c
drivers/devfreq/Kconfig +12 -0
index defe1d438710..9088a151bafe 100644
@@ -90,10 +90,22 @@ config ARM_EXYNOS_BUS_DEVFREQ
 	  Each memory bus group could contain many memoby bus block. It reads
 	  PPMU counters of memory controllers by using DEVFREQ-event device
 	  and adjusts the operating frequencies and voltages with OPP support.
 	  This does not yet operate with optimal voltages.
 
+config ARM_IMX_DEVFREQ
+	tristate "i.MX DEVFREQ Driver"
+	depends on ARCH_MXC || COMPILE_TEST
+	select DEVFREQ_GOV_PASSIVE
+	select DEVFREQ_GOV_SIMPLE_ONDEMAND
+	select DEVFREQ_GOV_USERSPACE
+	select PM_OPP
+	help
+	  This adds the DEVFREQ driver for the i.MX family of SoCs.
+	  It allows adjusting frequencies for DDRC (DDR Controller) and various
+	  NICs and NOCs which form the SOC interconnect fabric
+
 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 1ac92614b6aa..1c1f35f74d24 100644
@@ -8,10 +8,11 @@ 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_DEVFREQ)		+= imx-ddrc.o
+obj-$(CONFIG_ARM_IMX_DEVFREQ)		+= imx-devfreq.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
 
 # DEVFREQ Event Drivers
drivers/devfreq/imx-devfreq.c new file +148 -0

148 lines not on this page · raw message

Signature · 1 line
2.17.1
#5 lore raw

RFC PATCH v5 3/10 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-devfreq.c | 37 +++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)
drivers/devfreq/imx-devfreq.c +37 -0
index 5c907b3ab9c0..241d4c00db1f 100644
@@ -15,10 +15,11 @@
 struct imx_devfreq {
 	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_devfreq_target(struct device *dev, unsigned long *freq, u32 flags)
 {
 	struct imx_devfreq *priv = dev_get_drvdata(dev);
@@ -59,11 +60,40 @@ static int imx_devfreq_get_dev_status(struct device *dev,
 	return 0;
 }
 
 static void imx_devfreq_exit(struct device *dev)
 {
+	struct imx_devfreq *priv = dev_get_drvdata(dev);
+
 	dev_pm_opp_of_remove_table(dev);
+	platform_device_unregister(priv->icc_pdev);
+}
+
+/* imx_devfreq_init_icc() - register matching icc provider if required */
+static int imx_devfreq_init_icc(struct device *dev)
+{
+	struct imx_devfreq *priv = dev_get_drvdata(dev);
+	const char *icc_driver_name;
+
+	if (!IS_ENABLED(CONFIG_INTERCONNECT_IMX))
+		return 0;
+	if (!of_get_property(dev->of_node, "#interconnect-cells", 0))
+		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, 0, 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_devfreq_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -118,18 +148,25 @@ static int imx_devfreq_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_devfreq_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_devfreq_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_devfreq_of_match);
Signature · 1 line
2.17.1
#6 lore raw

RFC PATCH v5 4/10 PM / devfreq: Add devfreq_get_devfreq_by_node

In reply to Leonard Crestez

Split off part of devfreq_get_devfreq_by_phandle into a separate function. This allows callers to fetch devfreq instances by enumerating devicetree instead of explicit phandles.

---
 drivers/devfreq/devfreq.c | 42 +++++++++++++++++++++++++++++----------
 include/linux/devfreq.h   |  1 +
 2 files changed, 32 insertions(+), 11 deletions(-)
drivers/devfreq/devfreq.c +31 -11
index dab31b63eb10..bc83d0aab279 100644
@@ -931,10 +931,33 @@ struct devfreq *devm_devfreq_add_device(struct device *dev,
 	return devfreq;
 }
 EXPORT_SYMBOL(devm_devfreq_add_device);
 
 #ifdef CONFIG_OF
+/*
+ * devfreq_get_devfreq_by_node - Get the devfreq device from devicetree
+ * @np - pointer to device_node
+ *
+ * return the instance of devfreq device
+ */
+struct devfreq *devfreq_get_devfreq_by_node(struct device_node *node)
+{
+	struct devfreq *devfreq;
+
+	mutex_lock(&devfreq_list_lock);
+	list_for_each_entry(devfreq, &devfreq_list, node) {
+		if (devfreq->dev.parent
+			&& devfreq->dev.parent->of_node == node) {
+			mutex_unlock(&devfreq_list_lock);
+			return devfreq;
+		}
+	}
+	mutex_unlock(&devfreq_list_lock);
+
+	return ERR_PTR(-EPROBE_DEFER);
+}
+
 /*
  * devfreq_get_devfreq_by_phandle - Get the devfreq device from devicetree
  * @dev - instance to the given device
  * @index - index into list of devfreq
  *
@@ -953,25 +976,22 @@ struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev, int index)
 
 	node = of_parse_phandle(dev->of_node, "devfreq", index);
 	if (!node)
 		return ERR_PTR(-ENODEV);
 
-	mutex_lock(&devfreq_list_lock);
-	list_for_each_entry(devfreq, &devfreq_list, node) {
-		if (devfreq->dev.parent
-			&& devfreq->dev.parent->of_node == node) {
-			mutex_unlock(&devfreq_list_lock);
-			of_node_put(node);
-			return devfreq;
-		}
-	}
-	mutex_unlock(&devfreq_list_lock);
+	devfreq = devfreq_get_devfreq_by_node(node);
 	of_node_put(node);
 
-	return ERR_PTR(-EPROBE_DEFER);
+	return devfreq;
 }
+
 #else
+struct devfreq *devfreq_get_devfreq_by_node(struct device_node *node)
+{
+	return ERR_PTR(-ENODEV);
+}
+
 struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev, int index)
 {
 	return ERR_PTR(-ENODEV);
 }
 #endif /* CONFIG_OF */
include/linux/devfreq.h +1 -0
index fb376b5b7281..d4d1ec04aeea 100644
@@ -242,10 +242,11 @@ extern int devm_devfreq_register_notifier(struct device *dev,
 				unsigned int list);
 extern void devm_devfreq_unregister_notifier(struct device *dev,
 				struct devfreq *devfreq,
 				struct notifier_block *nb,
 				unsigned int list);
+extern struct devfreq *devfreq_get_devfreq_by_node(struct device_node *node);
 extern struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev,
 						int index);
 
 #if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)
 /**
Signature · 1 line
2.17.1
#7 lore raw

RFC PATCH v5 5/10 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 adjustable nodes are found based on an "interconnect-node-id" property by scanning the entire device tree.

The interconnect provider doesn't need an virtual OF node, instead those same adjustable nodes are registered as proxies which xlate to the platform-level provider.

The platform device for the interconnect needs to be registered from a SOC driver (similar to cpufreq).

---
 drivers/interconnect/Kconfig      |   1 +
 drivers/interconnect/Makefile     |   1 +
 drivers/interconnect/imx/Kconfig  |   5 +
 drivers/interconnect/imx/Makefile |   1 +
 drivers/interconnect/imx/imx.c    | 273 ++++++++++++++++++++++++++++++
 drivers/interconnect/imx/imx.h    |  60 +++++++
 6 files changed, 341 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 b6ea8f0a6122..f57e77b8731c 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 28f2ab0824d5..20a13b7eb37f 100644
@@ -2,5 +2,6 @@
 
 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..7d81d3c83a61
@@ -0,0 +1,5 @@
+config INTERCONNECT_IMX
+	bool "i.MX interconnect drivers"
+	depends on ARCH_MXC || COMPILE_TEST
+	help
+	  Generic interconnect driver for i.MX SOCs
drivers/interconnect/imx/Makefile new file +1 -0
new file mode 100644
index 000000000000..bb92fd9fe4a5
@@ -0,0 +1 @@
+obj-$(CONFIG_INTERCONNECT_IMX) += imx.o
drivers/interconnect/imx/imx.c new file +273 -0

273 lines not on this page · raw message

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

60 lines not on this page · raw message

Signature · 1 line
2.17.1
#8 lore raw

Re: [PATCH RFC v5 05/10] interconnect: Add imx core driver

Hi Leonard,

Thanks for the patch!

Quoted 8 lines · 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 adjustable nodes are found based on an "interconnect-node-id" property by scanning the entire device tree.

Are the adjustable nodes SoC specific? Can we have them here in the driver instead of scanning the entire device tree?

Quoted 83 lines

The interconnect provider doesn't need an virtual OF node, instead those same adjustable nodes are registered as proxies which xlate to the platform-level provider.

The platform device for the interconnect needs to be registered from a SOC driver (similar to cpufreq).

---
 drivers/interconnect/Kconfig      |   1 +
 drivers/interconnect/Makefile     |   1 +
 drivers/interconnect/imx/Kconfig  |   5 +
 drivers/interconnect/imx/Makefile |   1 +
 drivers/interconnect/imx/imx.c    | 273 ++++++++++++++++++++++++++++++
 drivers/interconnect/imx/imx.h    |  60 +++++++
 6 files changed, 341 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 b6ea8f0a6122..f57e77b8731c 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 28f2ab0824d5..20a13b7eb37f 100644
@@ -2,5 +2,6 @@
 
 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..7d81d3c83a61
@@ -0,0 +1,5 @@
+config INTERCONNECT_IMX
+	bool "i.MX interconnect drivers"
+	depends on ARCH_MXC || COMPILE_TEST
+	help
+	  Generic interconnect driver for i.MX SOCs
drivers/interconnect/imx/Makefile new file +1 -0
new file mode 100644
index 000000000000..bb92fd9fe4a5
@@ -0,0 +1 @@
+obj-$(CONFIG_INTERCONNECT_IMX) += imx.o
drivers/interconnect/imx/imx.c new file +13 -0
new file mode 100644
index 000000000000..7d248e01dcf0
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Interconnect framework driver for i.MX SoC
+ *
+ * Copyright (c) 2019, BayLibre
+ * Copyright (c) 2019, NXP
+ * Author: Alexandre Bailon <[email protected]>
+ * Author: Leonard Crestez <[email protected]>
+ */
+
+#include <linux/devfreq.h>
+#include <linux/device.h>
+#include <linux/interconnect-provider.h>

drivers/interconnect/imx/imx.c line 23

Quoted 10 lines
drivers/interconnect/imx/imx.c new file +10 -0
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+
+#include "imx.h"
+
+/* private icc_provider data */
+struct imx_icc_provider {
+	struct device *dev;

What device is this? There is already a *dev in struct icc_provider. Please add kernel-doc.

Quoted 33 lines
drivers/interconnect/imx/imx.c new file +33 -0
+};
+
+/* private icc_node data */
+struct imx_icc_node {
+	const struct imx_icc_node_desc *desc;
+	struct devfreq *devfreq;
+	struct dev_pm_qos_request qos_req;
+};
+
+static int imx_icc_aggregate(struct icc_node *node, u32 tag,
+			     u32 avg_bw, u32 peak_bw,
+			     u32 *agg_avg, u32 *agg_peak)
+{
+	*agg_avg += avg_bw;
+	*agg_peak = max(*agg_peak, peak_bw);
+
+	return 0;
+}
+
+static struct icc_node *imx_icc_xlate(struct of_phandle_args *spec, void *data)
+{
+	struct imx_icc_provider *desc = data;
+	struct icc_provider *provider = dev_get_drvdata(desc->dev);
+	unsigned int id = spec->args[0];
+	struct icc_node *node;
+
+	list_for_each_entry(node, &provider->nodes, node_list)
+		if (node->id == id)
+			return node;
+
+	return ERR_PTR(-EINVAL);
+}
+

drivers/interconnect/imx/imx.c line 66

Quoted 10 lines
drivers/interconnect/imx/imx.c new file +10 -0
+static int imx_icc_node_set(struct icc_node *node)
+{
+	struct device *dev = node->provider->dev;
+	struct imx_icc_node *node_data = node->data;
+	u64 freq;
+
+	if (!node_data->devfreq)
+		return 0;
+
+	freq = (node->avg_bw + node->peak_bw) * node_data->desc->adj->bw_mul;

Why the sum of average and peak bandwidth?

Quoted 38 lines
drivers/interconnect/imx/imx.c new file +38 -0
+	do_div(freq, node_data->desc->adj->bw_div);
+	dev_dbg(dev, "node %s device %s avg_bw %ukBps peak_bw %ukBps min_freq %llukHz\n",
+			node->name, dev_name(node_data->devfreq->dev.parent),
+			node->avg_bw, node->peak_bw, freq);
+
+	if (freq > S32_MAX) {
+		dev_err(dev, "%s can't request more than S32_MAX freq\n",
+				node->name);
+		return -ERANGE;
+	}
+
+	dev_pm_qos_update_request(&node_data->qos_req, freq);
+
+	return 0;
+}
+
+static int imx_icc_set(struct icc_node *src, struct icc_node *dst)
+{
+	return imx_icc_node_set(dst);
+}
+
+static int imx_icc_node_init_devfreq(struct device *dev,
+				     struct icc_node *node)
+{
+	struct imx_icc_node *node_data = node->data;
+	struct device_node *dn;
+	u32 node_id;
+	int ret;
+
+	/* Find nodes based on interconnect-node-id property */
+	for_each_node_with_property(dn, "interconnect-node-id") {
+		ret = of_property_read_u32(dn, "interconnect-node-id",
+					   &node_id);
+		if (ret != 0)
+			continue;
+
+		if (node_id == node->id) {
+			of_node_get(dn);

drivers/interconnect/imx/imx.c line 114

Quoted 10 lines
drivers/interconnect/imx/imx.c new file +10 -0
+			break;
+		}
+	}
+
+	if (!dn)
+		return 0;
+
+	dev_info(dev, "node %s[%d] has device node %pOF\n",
+			node->name, node->id, dn);
+	node_data->devfreq = devfreq_get_devfreq_by_node(dn);

Ah, so you need to get the devfreq nodes? So looking at the next patches it seems that noc and ddrc are the only adjustable nodes?

Maybe we should model them both as interconnect providers, as they seem to be dealing with the bandwidth/frequency requirements and changing the clock rates.

Thanks,
Georgi

Quoted 15 lines
drivers/interconnect/imx/imx.c new file +15 -0
+	if (IS_ERR(node_data->devfreq)) {
+		of_node_put(dn);
+		ret = PTR_ERR(node_data->devfreq);
+		dev_err(dev, "failed to fetch devfreq for %s: %d\n",
+				node->name, ret);
+		return ret;
+	}
+
+	of_node_put(dn);
+
+	return dev_pm_qos_add_request(node_data->devfreq->dev.parent,
+				      &node_data->qos_req,
+				      DEV_PM_QOS_MIN_FREQUENCY, 0);
+}
+
#9 lore raw

Re: [PATCH RFC v5 05/10] interconnect: Add imx core driver

Quoted 105 lines · Georgi Djakov

Hi Leonard,

Thanks for the patch!

Quoted 8 lines · 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 adjustable nodes are found based on an "interconnect-node-id" property by scanning the entire device tree.

Are the adjustable nodes SoC specific? Can we have them here in the driver instead of scanning the entire device tree?

Quoted 88 lines

The interconnect provider doesn't need an virtual OF node, instead those same adjustable nodes are registered as proxies which xlate to the platform-level provider.

The platform device for the interconnect needs to be registered from a SOC driver (similar to cpufreq).

---
  drivers/interconnect/Kconfig      |   1 +
  drivers/interconnect/Makefile     |   1 +
  drivers/interconnect/imx/Kconfig  |   5 +
  drivers/interconnect/imx/Makefile |   1 +
  drivers/interconnect/imx/imx.c    | 273 ++++++++++++++++++++++++++++++
  drivers/interconnect/imx/imx.h    |  60 +++++++
  6 files changed, 341 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 b6ea8f0a6122..f57e77b8731c 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 28f2ab0824d5..20a13b7eb37f 100644
@@ -2,5 +2,6 @@
 
  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..7d81d3c83a61
@@ -0,0 +1,5 @@
+config INTERCONNECT_IMX
+	bool "i.MX interconnect drivers"
+	depends on ARCH_MXC || COMPILE_TEST
+	help
+	  Generic interconnect driver for i.MX SOCs
drivers/interconnect/imx/Makefile new file +1 -0
new file mode 100644
index 000000000000..bb92fd9fe4a5
@@ -0,0 +1 @@
+obj-$(CONFIG_INTERCONNECT_IMX) += imx.o
drivers/interconnect/imx/imx.c new file +18 -0
new file mode 100644
index 000000000000..7d248e01dcf0
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Interconnect framework driver for i.MX SoC
+ *
+ * Copyright (c) 2019, BayLibre
+ * Copyright (c) 2019, NXP
+ * Author: Alexandre Bailon <[email protected]>
+ * Author: Leonard Crestez <[email protected]>
+ */
+
+#include <linux/devfreq.h>
+#include <linux/device.h>
+#include <linux/interconnect-provider.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+
Quoted 8 lines

drivers/interconnect/imx/imx.c line 23

Quoted 5 lines
drivers/interconnect/imx/imx.c new file +5 -0
+#include "imx.h"
+
+/* private icc_provider data */
+struct imx_icc_provider {
+	struct device *dev;

What device is this? There is already a *dev in struct icc_provider. Please add kernel-doc.

This is set as icc_provider->data and used for xlate but it can be removed entirely if driver switches to icc_xlate_onecell.

Quoted 35 lines
Quoted 35 lines
drivers/interconnect/imx/imx.c new file +35 -0
+/* private icc_node data */
+struct imx_icc_node {
+	const struct imx_icc_node_desc *desc;
+	struct devfreq *devfreq;
+	struct dev_pm_qos_request qos_req;
+};
+
+static int imx_icc_aggregate(struct icc_node *node, u32 tag,
+			     u32 avg_bw, u32 peak_bw,
+			     u32 *agg_avg, u32 *agg_peak)
+{
+	*agg_avg += avg_bw;
+	*agg_peak = max(*agg_peak, peak_bw);
+
+	return 0;
+}
+
+static struct icc_node *imx_icc_xlate(struct of_phandle_args *spec, void *data)
+{
+	struct imx_icc_provider *desc = data;
+	struct icc_provider *provider = dev_get_drvdata(desc->dev);
+	unsigned int id = spec->args[0];
+	struct icc_node *node;
+
+	list_for_each_entry(node, &provider->nodes, node_list)
+		if (node->id == id)
+			return node;
+
+	return ERR_PTR(-EINVAL);
+}
+
+static int imx_icc_node_set(struct icc_node *node)
+{
+	struct device *dev = node->provider->dev;
+	struct imx_icc_node *node_data = node->data;
Quoted 8 lines

drivers/interconnect/imx/imx.c line 66

Quoted 6 lines
drivers/interconnect/imx/imx.c new file +6 -0
+	u64 freq;
+
+	if (!node_data->devfreq)
+		return 0;
+
+	freq = (node->avg_bw + node->peak_bw) * node_data->desc->adj->bw_mul;

Why the sum of average and peak bandwidth?

What else?

Averages from all path requests are added and the max() of all per-path peak requests is added on top. The average BW is guaranteed to be consumed (for example a display controller) and the BW for occasional bursts (such as USB) should be reserved on top of that.

Using max(avg, peak) here would make requests for peak BW largely ineffective when there's also a large "avg" request.

Quoted 43 lines
Quoted 43 lines
drivers/interconnect/imx/imx.c new file +43 -0
+	do_div(freq, node_data->desc->adj->bw_div);
+	dev_dbg(dev, "node %s device %s avg_bw %ukBps peak_bw %ukBps min_freq %llukHz\n",
+			node->name, dev_name(node_data->devfreq->dev.parent),
+			node->avg_bw, node->peak_bw, freq);
+
+	if (freq > S32_MAX) {
+		dev_err(dev, "%s can't request more than S32_MAX freq\n",
+				node->name);
+		return -ERANGE;
+	}
+
+	dev_pm_qos_update_request(&node_data->qos_req, freq);
+
+	return 0;
+}
+
+static int imx_icc_set(struct icc_node *src, struct icc_node *dst)
+{
+	return imx_icc_node_set(dst);
+}
+
+static int imx_icc_node_init_devfreq(struct device *dev,
+				     struct icc_node *node)
+{
+	struct imx_icc_node *node_data = node->data;
+	struct device_node *dn;
+	u32 node_id;
+	int ret;
+
+	/* Find nodes based on interconnect-node-id property */
+	for_each_node_with_property(dn, "interconnect-node-id") {
+		ret = of_property_read_u32(dn, "interconnect-node-id",
+					   &node_id);
+		if (ret != 0)
+			continue;
+
+		if (node_id == node->id) {
+			of_node_get(dn);
+			break;
+		}
+	}
+
+	if (!dn)
Quoted 8 lines

drivers/interconnect/imx/imx.c line 114

Quoted 5 lines
drivers/interconnect/imx/imx.c new file +5 -0
+		return 0;
+
+	dev_info(dev, "node %s[%d] has device node %pOF\n",
+			node->name, node->id, dn);
+	node_data->devfreq = devfreq_get_devfreq_by_node(dn);

Ah, so you need to get the devfreq nodes? So looking at the next patches it seems that noc and ddrc are the only adjustable nodes?

I want to add more scalable nodes in the future. imx8mq/8mm/8mn have additional NICs (AXI switches with a different implementation) and upcoming imx8mp will have additional NOCs and scalable NTTP links.

Quoted 3 lines

Maybe we should model them both as interconnect providers, as they seem to be dealing with the bandwidth/frequency requirements and changing the clock rates.

The ddrc is not really an interconnect, it only has an AXI slave port. In theory it could register itself as a single-node icc provider solely so that it can handle the "set" call but that seems hacky.

Current icc driver implementations send aggregated BW requests to a separate controller and internally it changes some frequencies, correct? What I'm doing is implementing the frequency adjustment part inside the kernel as devfreq drivers. These devices have their own OF nodes with OPP tables and supply regulators and governors (based on bandwith measurement).

It makes a lot of sense to layer the "interconnect" on top of "scalable nodes".

--
Regards,
Leonard

#10 lore raw

RFC PATCH v5 6/10 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         |   1 +
 drivers/interconnect/imx/imx8mm.c         | 105 ++++++++++++++++++++++
 include/dt-bindings/interconnect/imx8mm.h |  49 ++++++++++
 4 files changed, 159 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 7d81d3c83a61..15671fe7f600 100644
@@ -1,5 +1,9 @@
 config INTERCONNECT_IMX
 	bool "i.MX interconnect drivers"
 	depends on ARCH_MXC || COMPILE_TEST
 	help
 	  Generic interconnect driver for i.MX SOCs
+
+config INTERCONNECT_IMX8MM
+	def_bool y
+	depends on INTERCONNECT_IMX
drivers/interconnect/imx/Makefile +1 -0
index bb92fd9fe4a5..5f658c1608a6 100644
@@ -1 +1,2 @@
 obj-$(CONFIG_INTERCONNECT_IMX) += imx.o
+obj-$(CONFIG_INTERCONNECT_IMX8MM) += imx8mm.o
drivers/interconnect/imx/imx8mm.c new file +105 -0

105 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
#11 lore raw

RFC PATCH v5 7/10 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         |   1 +
 drivers/interconnect/imx/imx8mq.c         | 103 ++++++++++++++++++++++
 include/dt-bindings/interconnect/imx8mq.h |  48 ++++++++++
 4 files changed, 156 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 15671fe7f600..e0d36355eeb8 100644
@@ -5,5 +5,9 @@ config INTERCONNECT_IMX
 	  Generic interconnect driver for i.MX SOCs
 
 config INTERCONNECT_IMX8MM
 	def_bool y
 	depends on INTERCONNECT_IMX
+
+config INTERCONNECT_IMX8MQ
+	def_bool y
+	depends on INTERCONNECT_IMX
drivers/interconnect/imx/Makefile +1 -0
index 5f658c1608a6..8c5d6f9e47f5 100644
@@ -1,2 +1,3 @@
 obj-$(CONFIG_INTERCONNECT_IMX) += imx.o
 obj-$(CONFIG_INTERCONNECT_IMX8MM) += imx8mm.o
+obj-$(CONFIG_INTERCONNECT_IMX8MQ) += imx8mq.o
drivers/interconnect/imx/imx8mq.c new file +103 -0

103 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
#12 lore raw

RFC PATCH v5 8/10 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         |  1 +
 drivers/interconnect/imx/imx8mn.c         | 94 +++++++++++++++++++++++
 include/dt-bindings/interconnect/imx8mn.h | 41 ++++++++++
 4 files changed, 140 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 e0d36355eeb8..bc311e86d255 100644
@@ -6,8 +6,12 @@ config INTERCONNECT_IMX
 
 config INTERCONNECT_IMX8MM
 	def_bool y
 	depends on INTERCONNECT_IMX
 
+config INTERCONNECT_IMX8MN
+	def_bool y
+	depends on INTERCONNECT_IMX
+
 config INTERCONNECT_IMX8MQ
 	def_bool y
 	depends on INTERCONNECT_IMX
drivers/interconnect/imx/Makefile +1 -0
index 8c5d6f9e47f5..e39d6c6af3b7 100644
@@ -1,3 +1,4 @@
 obj-$(CONFIG_INTERCONNECT_IMX) += imx.o
 obj-$(CONFIG_INTERCONNECT_IMX8MM) += imx8mm.o
+obj-$(CONFIG_INTERCONNECT_IMX8MN) += imx8mn.o
 obj-$(CONFIG_INTERCONNECT_IMX8MQ) += imx8mq.o
drivers/interconnect/imx/imx8mn.c new file +94 -0

94 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
#13 lore raw

RFC PATCH v5 9/10 arm64: dts: imx8m: Add NOC nodes

In reply to Leonard Crestez

Add initial support for dynamic frequency scaling of main NOC.

Make DDRC the parent of the NOC (using passive governor) so that the main NOC is automatically scaled together with DDRC by default.

Support for proactive scaling via interconnect will come later.

---
 arch/arm64/boot/dts/freescale/imx8mm.dtsi | 22 ++++++++++++++++++++++
 arch/arm64/boot/dts/freescale/imx8mn.dtsi | 22 ++++++++++++++++++++++
 arch/arm64/boot/dts/freescale/imx8mq.dtsi | 22 ++++++++++++++++++++++
 3 files changed, 66 insertions(+)
arch/arm64/boot/dts/freescale/imx8mm.dtsi +22 -0
index 5404870d80d5..dc0ab49bbbd2 100644
@@ -138,10 +138,24 @@
 			clock-latency-ns = <150000>;
 			opp-suspend;
 		};
 	};
 
+	noc_opp_table: noc-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>;
+		};
+	};
+
 	memory@40000000 {
 		device_type = "memory";
 		reg = <0x0 0x40000000 0 0x80000000>;
 	};
 
@@ -772,10 +786,18 @@
 				status = "disabled";
 			};
 
 		};
 
+		noc: interconnect@32700000 {
+			compatible = "fsl,imx8mm-noc", "fsl,imx8m-noc";
+			reg = <0x32700000 0x100000>;
+			clocks = <&clk IMX8MM_CLK_NOC>;
+			devfreq = <&ddrc>;
+			operating-points-v2 = <&noc_opp_table>;
+		};
+
 		aips4: bus@32c00000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
 			ranges = <0x32c00000 0x32c00000 0x400000>;
arch/arm64/boot/dts/freescale/imx8mn.dtsi +22 -0
index 344dd777635f..6b4a9ba2a8a5 100644
@@ -137,10 +137,24 @@
 			clock-latency-ns = <150000>;
 			opp-suspend;
 		};
 	};
 
+	noc_opp_table: noc-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>;
+		};
+	};
+
 	memory@40000000 {
 		device_type = "memory";
 		reg = <0x0 0x40000000 0 0x80000000>;
 	};
 
@@ -668,10 +682,18 @@
 				status = "disabled";
 			};
 
 		};
 
+		noc: interconnect@32700000 {
+			compatible = "fsl,imx8mn-noc", "fsl,imx8m-noc";
+			reg = <0x32700000 0x100000>;
+			clocks = <&clk IMX8MN_CLK_NOC>;
+			devfreq = <&ddrc>;
+			operating-points-v2 = <&noc_opp_table>;
+		};
+
 		aips4: bus@32c00000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			reg = <0x32c00000 0x400000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
arch/arm64/boot/dts/freescale/imx8mq.dtsi +22 -0
index 6ef1af41ef68..c42c67eb1d50 100644
@@ -183,10 +183,24 @@
 			clock-latency-ns = <150000>;
 			opp-suspend;
 		};
 	};
 
+	noc_opp_table: noc-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>;
+		};
+	};
+
 	pmu {
 		compatible = "arm,cortex-a53-pmu";
 		interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
 		interrupt-parent = <&gic>;
 		interrupt-affinity = <&A53_0>, <&A53_1>, <&A53_2>, <&A53_3>;
@@ -931,10 +945,18 @@
 				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>;
+			devfreq = <&ddrc>;
+			operating-points-v2 = <&noc_opp_table>;
+		};
+
 		bus@32c00000 { /* AIPS4 */
 			compatible = "fsl,imx8mq-aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
 			ranges = <0x32c00000 0x32c00000 0x400000>;
Signature · 1 line
2.17.1
#14 lore raw

RFC PATCH v5 10/10 arm64: dts: imx8m: Add interconnect provider properties

In reply to Leonard Crestez

Add #interconnect-cells on main &noc so that it will probe the platform interconnect providers. Other devices can request icc_paths like this:

interconnects = <&noc BUS_MASTER_ID &noc BUS_SLAVE_ID>

And interconnect-node-id properties on &noc and &ddrc, the interconnect provider will scan these and make PM QoS frequency requests in response to bandwith request from other drivers.

---
 arch/arm64/boot/dts/freescale/imx8mm.dtsi | 4 ++++
 arch/arm64/boot/dts/freescale/imx8mn.dtsi | 4 ++++
 arch/arm64/boot/dts/freescale/imx8mq.dtsi | 4 ++++
 3 files changed, 12 insertions(+)
arch/arm64/boot/dts/freescale/imx8mm.dtsi +4 -0
index dc0ab49bbbd2..4a84db1bf6bd 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>;
@@ -791,10 +792,12 @@
 		noc: interconnect@32700000 {
 			compatible = "fsl,imx8mm-noc", "fsl,imx8m-noc";
 			reg = <0x32700000 0x100000>;
 			clocks = <&clk IMX8MM_CLK_NOC>;
 			devfreq = <&ddrc>;
+			#interconnect-cells = <1>;
+			interconnect-node-id = <IMX8MM_ICN_NOC>;
 			operating-points-v2 = <&noc_opp_table>;
 		};
 
 		aips4: bus@32c00000 {
 			compatible = "fsl,aips-bus", "simple-bus";
@@ -881,10 +884,11 @@
 		};
 
 		ddrc: dram-controller@3d400000 {
 			compatible = "fsl,imx8mm-ddrc", "fsl,imx8m-ddrc";
 			reg = <0x3d400000 0x400000>;
+			interconnect-node-id = <IMX8MM_ICS_DRAM>;
 			clock-names = "dram_core",
 				      "dram_pll",
 				      "dram_alt",
 				      "dram_apb";
 			clocks = <&clk IMX8MM_CLK_DRAM_CORE>,
arch/arm64/boot/dts/freescale/imx8mn.dtsi +4 -0
index 6b4a9ba2a8a5..0fd96c976607 100644
@@ -5,10 +5,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/interconnect/imx8mn.h>
 
 #include "imx8mn-pinfunc.h"
 
 / {
 	interrupt-parent = <&gic>;
@@ -687,10 +688,12 @@
 		noc: interconnect@32700000 {
 			compatible = "fsl,imx8mn-noc", "fsl,imx8m-noc";
 			reg = <0x32700000 0x100000>;
 			clocks = <&clk IMX8MN_CLK_NOC>;
 			devfreq = <&ddrc>;
+			#interconnect-cells = <1>;
+			interconnect-node-id = <IMX8MN_ICN_NOC>;
 			operating-points-v2 = <&noc_opp_table>;
 		};
 
 		aips4: bus@32c00000 {
 			compatible = "fsl,aips-bus", "simple-bus";
@@ -790,10 +793,11 @@
 				      "dram_apb";
 			clocks = <&clk IMX8MN_CLK_DRAM_CORE>,
 				 <&clk IMX8MN_DRAM_PLL>,
 				 <&clk IMX8MN_CLK_DRAM_ALT>,
 				 <&clk IMX8MN_CLK_DRAM_APB>;
+			interconnect-node-id = <IMX8MN_ICS_DRAM>;
 			devfreq-events = <&ddr_pmu>;
 		};
 
 		ddr_pmu: ddr-pmu@3d800000 {
 			compatible = "fsl,imx8mn-ddr-pmu", "fsl,imx8m-ddr-pmu";
arch/arm64/boot/dts/freescale/imx8mq.dtsi +4 -0
index c42c67eb1d50..6ede02b44931 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>;
 
@@ -950,10 +951,12 @@
 		noc: interconnect@32700000 {
 			compatible = "fsl,imx8mq-noc", "fsl,imx8m-noc";
 			reg = <0x32700000 0x100000>;
 			clocks = <&clk IMX8MQ_CLK_NOC>;
 			devfreq = <&ddrc>;
+			#interconnect-cells = <1>;
+			interconnect-node-id = <IMX8MQ_ICN_NOC>;
 			operating-points-v2 = <&noc_opp_table>;
 		};
 
 		bus@32c00000 { /* AIPS4 */
 			compatible = "fsl,imx8mq-aips-bus", "simple-bus";
@@ -1144,10 +1147,11 @@
 				      "dram_apb";
 			clocks = <&clk IMX8MQ_CLK_DRAM_CORE>,
 				 <&clk IMX8MQ_DRAM_PLL_OUT>,
 				 <&clk IMX8MQ_CLK_DRAM_ALT>,
 				 <&clk IMX8MQ_CLK_DRAM_APB>;
+			interconnect-node-id = <IMX8MQ_ICS_DRAM>;
 			devfreq-events = <&ddr_pmu>;
 		};
 
 		ddr_pmu: ddr-pmu@3d800000 {
 			compatible = "fsl,imx8mq-ddr-pmu", "fsl,imx8m-ddr-pmu";
Signature · 1 line
2.17.1