linux-doc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms
@ 2025-07-11 14:48 Clément Le Goffic
  2025-07-11 14:48 ` [PATCH v2 01/16] bus: firewall: move stm32_firewall header file in include folder Clément Le Goffic
                   ` (16 more replies)
  0 siblings, 17 replies; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:48 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

This patch series introduces the DDR Performance Monitor (DDRPERFM) support for
STM32MP platforms.

The series firstly improves the STM32MP25 RCC driver to make it usable
as an access controller, needed for driver probe.

It also includes the addition of device tree bindings, the HDP driver,
documentation and updates to the device tree files for
STM32MP13, STM32MP15 and STM32MP25 SoCs.
The series also updates the MAINTAINERS file to include myself as the
maintainer for the STM32 DDR PMU driver.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
Changes in v2:
- MAINTAINERS:
    Due to reorganisation, my contract with ST ends at the end of this month
    and I will no longer have access to this mailbox.
    Therefore, I will be available for any mission related to embedded and
    kernel linux.
    Change email address in MAINTAINERS file for STM32 DDR PMU driver.
- devicetrees:
  -stm32mp257f-dk: add LPDDR4 channel
  -stm32mp257f-ev1: add DDR4 channel
- dt-bindings:
  - perf:
    - Change Maintainer email address
    - Drop obvious descriptions (clocks and reset property)
    - Drop redundant "bindings" in commit message
    - Drop unneedded "stm32mp151-ddr-pmu" compatible
    - s/st,dram-type/memory-channel/, memory-channel property is not in
      dtschema library so it will produce an error in the v2.
  - rcc:
    - Add required "access-controller-cells" property in example
  - ddr-channel:
    - Add bindings as per jedec,lpddrX-channel bindings
- driver:
  - Substitute the parsing of the 'st,dram-type' vendor devicetree
    property value with the parsing of the [lp]ddr channel compatible
  - Remove unneeded "stm32mp151-ddr-pmu" compatible
  - Use dev_err_probe when possible
  - Assert and deassert reset line unconditionnaly
  - Use `devm_reset_control_get_optional_exclusive` instead of
    `of_property_present` then `devm_reset_control_get`
  - Use `devm_clk_get_optional_prepared` instead of `of_property_present`
    then `devm_clk_get_prepared`
  - Disable and unprepare the clock at end of probe
  - Add io.h include as per LKP test report
  - Removed `of_match_ptr` reference in `platform_driver` struct
  - Add `pm_sleep_ptr` macro for `platform_driver` struct's `pm` field
  - Link to v1: https://lore.kernel.org/r/20250623-ddrperfm-upstream-v1-0-7dffff168090@foss.st.com

---
Clément Le Goffic (16):
      bus: firewall: move stm32_firewall header file in include folder
      dt-bindings: stm32: stm32mp25: add `access-controller-cell` property
      clk: stm32mp25: add firewall grant_access ops
      arm64: dts: st: set rcc as an access-controller
      dt-bindings: memory: add jedec,ddr[3-4]-channel binding
      arm64: dts: st: add LPDDR channel to stm32mp257f-dk board
      arm64: dts: st: add DDR channel to stm32mp257f-ev1 board
      dt-bindings: perf: stm32: introduce DDRPERFM dt-bindings
      perf: stm32: introduce DDRPERFM driver
      Documentation: perf: stm32: add ddrperfm support
      MAINTAINERS: add myself as STM32 DDR PMU maintainer
      ARM: dts: stm32: add ddrperfm on stm32mp131
      ARM: dts: stm32: add ddrperfm on stm32mp151
      arm64: dts: st: add ddrperfm on stm32mp251
      arm64: dts: st: support ddrperfm on stm32mp257f-dk
      arm64: dts: st: support ddrperfm on stm32mp257f-ev1

 Documentation/admin-guide/perf/index.rst           |   1 +
 Documentation/admin-guide/perf/stm32-ddr-pmu.rst   |  86 ++
 .../bindings/clock/st,stm32mp25-rcc.yaml           |   7 +
 .../memory-controllers/ddr/jedec,ddr-channel.yaml  |  53 ++
 .../devicetree/bindings/perf/st,stm32-ddr-pmu.yaml |  87 ++
 MAINTAINERS                                        |   7 +
 arch/arm/boot/dts/st/stm32mp131.dtsi               |   7 +
 arch/arm/boot/dts/st/stm32mp151.dtsi               |   7 +
 arch/arm64/boot/dts/st/stm32mp251.dtsi             |   8 +
 arch/arm64/boot/dts/st/stm32mp257f-dk.dts          |  12 +
 arch/arm64/boot/dts/st/stm32mp257f-ev1.dts         |  10 +
 drivers/bus/stm32_etzpc.c                          |   3 +-
 drivers/bus/stm32_firewall.c                       |   3 +-
 drivers/bus/stm32_rifsc.c                          |   3 +-
 drivers/clk/stm32/clk-stm32mp25.c                  |  40 +-
 drivers/perf/Kconfig                               |  11 +
 drivers/perf/Makefile                              |   1 +
 drivers/perf/stm32_ddr_pmu.c                       | 910 +++++++++++++++++++++
 {drivers => include/linux}/bus/stm32_firewall.h    |   0
 19 files changed, 1249 insertions(+), 7 deletions(-)
---
base-commit: d7b8f8e20813f0179d8ef519541a3527e7661d3a
change-id: 20250526-ddrperfm-upstream-bf07f57775da

Best regards,
--  
Clément Le Goffic <clement.legoffic@foss.st.com>


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH v2 01/16] bus: firewall: move stm32_firewall header file in include folder
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
@ 2025-07-11 14:48 ` Clément Le Goffic
  2025-07-11 14:48 ` [PATCH v2 02/16] dt-bindings: stm32: stm32mp25: add `access-controller-cell` property Clément Le Goffic
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:48 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

Other driver than rifsc and etzpc can implement firewall ops, such as
rcc.
In order for them to have access to the ops and type of this framework,
we need to get the `stm32_firewall.h` file in the include/ folder.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
 drivers/bus/stm32_etzpc.c                       | 3 +--
 drivers/bus/stm32_firewall.c                    | 3 +--
 drivers/bus/stm32_rifsc.c                       | 3 +--
 {drivers => include/linux}/bus/stm32_firewall.h | 0
 4 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/bus/stm32_etzpc.c b/drivers/bus/stm32_etzpc.c
index 7fc0f16960be..4918a14e507e 100644
--- a/drivers/bus/stm32_etzpc.c
+++ b/drivers/bus/stm32_etzpc.c
@@ -5,6 +5,7 @@
 
 #include <linux/bitfield.h>
 #include <linux/bits.h>
+#include <linux/bus/stm32_firewall.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/init.h>
@@ -16,8 +17,6 @@
 #include <linux/platform_device.h>
 #include <linux/types.h>
 
-#include "stm32_firewall.h"
-
 /*
  * ETZPC registers
  */
diff --git a/drivers/bus/stm32_firewall.c b/drivers/bus/stm32_firewall.c
index 2fc9761dadec..ef4988054b44 100644
--- a/drivers/bus/stm32_firewall.c
+++ b/drivers/bus/stm32_firewall.c
@@ -5,6 +5,7 @@
 
 #include <linux/bitfield.h>
 #include <linux/bits.h>
+#include <linux/bus/stm32_firewall.h>
 #include <linux/bus/stm32_firewall_device.h>
 #include <linux/device.h>
 #include <linux/err.h>
@@ -18,8 +19,6 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 
-#include "stm32_firewall.h"
-
 /* Corresponds to STM32_FIREWALL_MAX_EXTRA_ARGS + firewall ID */
 #define STM32_FIREWALL_MAX_ARGS		(STM32_FIREWALL_MAX_EXTRA_ARGS + 1)
 
diff --git a/drivers/bus/stm32_rifsc.c b/drivers/bus/stm32_rifsc.c
index 4cf1b60014b7..643ddd0a5f54 100644
--- a/drivers/bus/stm32_rifsc.c
+++ b/drivers/bus/stm32_rifsc.c
@@ -5,6 +5,7 @@
 
 #include <linux/bitfield.h>
 #include <linux/bits.h>
+#include <linux/bus/stm32_firewall.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/init.h>
@@ -16,8 +17,6 @@
 #include <linux/platform_device.h>
 #include <linux/types.h>
 
-#include "stm32_firewall.h"
-
 /*
  * RIFSC offset register
  */
diff --git a/drivers/bus/stm32_firewall.h b/include/linux/bus/stm32_firewall.h
similarity index 100%
rename from drivers/bus/stm32_firewall.h
rename to include/linux/bus/stm32_firewall.h

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 02/16] dt-bindings: stm32: stm32mp25: add `access-controller-cell` property
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
  2025-07-11 14:48 ` [PATCH v2 01/16] bus: firewall: move stm32_firewall header file in include folder Clément Le Goffic
@ 2025-07-11 14:48 ` Clément Le Goffic
  2025-07-15  3:17   ` Rob Herring
  2025-07-11 14:48 ` [PATCH v2 03/16] clk: stm32mp25: add firewall grant_access ops Clément Le Goffic
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:48 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

RCC is able to check the availability of a clock.
Allow to query the RCC with a firewall ID.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
 Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml b/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml
index 88e52f10d1ec..4d471e3d89bc 100644
--- a/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml
+++ b/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml
@@ -31,6 +31,11 @@ properties:
   '#reset-cells':
     const: 1
 
+  '#access-controller-cells':
+    const: 1
+    description:
+      Contains the firewall ID associated to the peripheral.
+
   clocks:
     items:
       - description: CK_SCMI_HSE High Speed External oscillator (8 to 48 MHz)
@@ -123,6 +128,7 @@ required:
   - reg
   - '#clock-cells'
   - '#reset-cells'
+  - '#access-controller-cells'
   - clocks
 
 additionalProperties: false
@@ -136,6 +142,7 @@ examples:
         reg = <0x44200000 0x10000>;
         #clock-cells = <1>;
         #reset-cells = <1>;
+        #access-controller-cells = <1>;
         clocks =  <&scmi_clk CK_SCMI_HSE>,
                   <&scmi_clk CK_SCMI_HSI>,
                   <&scmi_clk CK_SCMI_MSI>,

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 03/16] clk: stm32mp25: add firewall grant_access ops
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
  2025-07-11 14:48 ` [PATCH v2 01/16] bus: firewall: move stm32_firewall header file in include folder Clément Le Goffic
  2025-07-11 14:48 ` [PATCH v2 02/16] dt-bindings: stm32: stm32mp25: add `access-controller-cell` property Clément Le Goffic
@ 2025-07-11 14:48 ` Clément Le Goffic
  2025-07-11 14:48 ` [PATCH v2 04/16] arm64: dts: st: set rcc as an access-controller Clément Le Goffic
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:48 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

On STM32MP25, the RCC peripheral manages the secure level of resources
that are used by other devices such as clocks.
Declare this peripheral as a firewall controller.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
 drivers/clk/stm32/clk-stm32mp25.c | 40 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/stm32/clk-stm32mp25.c b/drivers/clk/stm32/clk-stm32mp25.c
index 52f0e8a12926..af4bc06d703a 100644
--- a/drivers/clk/stm32/clk-stm32mp25.c
+++ b/drivers/clk/stm32/clk-stm32mp25.c
@@ -4,8 +4,10 @@
  * Author: Gabriel Fernandez <gabriel.fernandez@foss.st.com> for STMicroelectronics.
  */
 
+#include <linux/bus/stm32_firewall.h>
 #include <linux/bus/stm32_firewall_device.h>
 #include <linux/clk-provider.h>
+#include <linux/device.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
 
@@ -1602,6 +1604,11 @@ static int stm32_rcc_get_access(void __iomem *base, u32 index)
 	return 0;
 }
 
+static int stm32mp25_rcc_grant_access(struct stm32_firewall_controller *ctrl, u32 firewall_id)
+{
+	return stm32_rcc_get_access(ctrl->mmio, firewall_id);
+}
+
 static int stm32mp25_check_security(struct device_node *np, void __iomem *base,
 				    const struct clock_config *cfg)
 {
@@ -1970,6 +1977,7 @@ MODULE_DEVICE_TABLE(of, stm32mp25_match_data);
 
 static int stm32mp25_rcc_clocks_probe(struct platform_device *pdev)
 {
+	struct stm32_firewall_controller *rcc_controller;
 	struct device *dev = &pdev->dev;
 	void __iomem *base;
 	int ret;
@@ -1982,7 +1990,36 @@ static int stm32mp25_rcc_clocks_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	return stm32_rcc_init(dev, stm32mp25_match_data, base);
+	ret = stm32_rcc_init(dev, stm32mp25_match_data, base);
+	if (ret)
+		return ret;
+
+	rcc_controller = devm_kzalloc(&pdev->dev, sizeof(*rcc_controller), GFP_KERNEL);
+	if (!rcc_controller)
+		return -ENOMEM;
+
+	rcc_controller->dev = dev;
+	rcc_controller->mmio = base;
+	rcc_controller->name = dev_driver_string(dev);
+	rcc_controller->type = STM32_PERIPHERAL_FIREWALL;
+	rcc_controller->grant_access = stm32mp25_rcc_grant_access;
+
+	platform_set_drvdata(pdev, rcc_controller);
+
+	ret = stm32_firewall_controller_register(rcc_controller);
+	if (ret) {
+		dev_err(dev, "Couldn't register as a firewall controller: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void stm32mp25_rcc_clocks_remove(struct platform_device *pdev)
+{
+	struct stm32_firewall_controller *rcc_controller = platform_get_drvdata(pdev);
+
+	stm32_firewall_controller_unregister(rcc_controller);
 }
 
 static struct platform_driver stm32mp25_rcc_clocks_driver = {
@@ -1991,6 +2028,7 @@ static struct platform_driver stm32mp25_rcc_clocks_driver = {
 		.of_match_table = stm32mp25_match_data,
 	},
 	.probe = stm32mp25_rcc_clocks_probe,
+	.remove = stm32mp25_rcc_clocks_remove,
 };
 
 static int __init stm32mp25_clocks_init(void)

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 04/16] arm64: dts: st: set rcc as an access-controller
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
                   ` (2 preceding siblings ...)
  2025-07-11 14:48 ` [PATCH v2 03/16] clk: stm32mp25: add firewall grant_access ops Clément Le Goffic
@ 2025-07-11 14:48 ` Clément Le Goffic
  2025-07-11 14:48 ` [PATCH v2 05/16] dt-bindings: memory: add jedec,ddr[3-4]-channel binding Clément Le Goffic
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:48 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

RCC now implements firewall access ops to check the access to
resources. Allow client nodes to query the RCC with one firewall ID.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp251.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
index 8d87865850a7..0683c2d5cb6f 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -1153,6 +1153,7 @@ rcc: clock-controller@44200000 {
 			reg = <0x44200000 0x10000>;
 			#clock-cells = <1>;
 			#reset-cells = <1>;
+			#access-controller-cells = <1>;
 			clocks = <&scmi_clk CK_SCMI_HSE>,
 				<&scmi_clk CK_SCMI_HSI>,
 				<&scmi_clk CK_SCMI_MSI>,

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 05/16] dt-bindings: memory: add jedec,ddr[3-4]-channel binding
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
                   ` (3 preceding siblings ...)
  2025-07-11 14:48 ` [PATCH v2 04/16] arm64: dts: st: set rcc as an access-controller Clément Le Goffic
@ 2025-07-11 14:48 ` Clément Le Goffic
  2025-07-21 20:09   ` Rob Herring
  2025-07-11 14:48 ` [PATCH v2 06/16] arm64: dts: st: add LPDDR channel to stm32mp257f-dk board Clément Le Goffic
                   ` (11 subsequent siblings)
  16 siblings, 1 reply; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:48 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

Introduce as per jedec,lpddrX-channel binding, jdec,ddr[3-4]-channel
binding.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
 .../memory-controllers/ddr/jedec,ddr-channel.yaml  | 53 ++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,ddr-channel.yaml b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,ddr-channel.yaml
new file mode 100644
index 000000000000..31daa22bcd4a
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,ddr-channel.yaml
@@ -0,0 +1,53 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,ddr-channel.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: DDR channel with chip/rank topology description
+
+description:
+  A DDR channel is a logical grouping of memory chips that are connected
+  to a host system. The main purpose of this node is to describe the
+  overall DDR topology of the system, including the amount of individual
+  DDR chips.
+
+maintainers:
+  - Clément Le Goffic <legoffic.clement@gmail.com>
+
+properties:
+  compatible:
+    enum:
+      - jedec,ddr3-channel
+      - jedec,ddr4-channel
+
+  io-width:
+    description:
+      The number of DQ pins in the channel. If this number is different
+      from (a multiple of) the io-width of the DDR chip, that means that
+      multiple instances of that type of chip are wired in parallel on this
+      channel (with the channel's DQ pins split up between the different
+      chips, and the CA, CS, etc. pins of the different chips all shorted
+      together).  This means that the total physical memory controlled by a
+      channel is equal to the sum of the densities of each rank on the
+      connected DDR chip, times the io-width of the channel divided by
+      the io-width of the DDR chip.
+    enum:
+      - 8
+      - 16
+      - 32
+      - 64
+      - 128
+
+required:
+  - compatible
+  - io-width
+
+additionalProperties: false
+
+examples:
+  - |
+    ddr_channel: ddr3-channel {
+        compatible = "jedec,ddr3-channel";
+        io-width = <16>;
+    };

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 06/16] arm64: dts: st: add LPDDR channel to stm32mp257f-dk board
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
                   ` (4 preceding siblings ...)
  2025-07-11 14:48 ` [PATCH v2 05/16] dt-bindings: memory: add jedec,ddr[3-4]-channel binding Clément Le Goffic
@ 2025-07-11 14:48 ` Clément Le Goffic
  2025-07-15  3:20   ` Rob Herring
  2025-07-11 14:48 ` [PATCH v2 07/16] arm64: dts: st: add DDR channel to stm32mp257f-ev1 board Clément Le Goffic
                   ` (10 subsequent siblings)
  16 siblings, 1 reply; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:48 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

Add 32bits LPDDR4 channel to the stm32mp257f-dk board.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp257f-dk.dts | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp257f-dk.dts b/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
index a278a1e3ce03..a97b41f14ecc 100644
--- a/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
+++ b/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
@@ -54,6 +54,13 @@ led-blue {
 		};
 	};
 
+	lpddr_channel: lpddr4-channel {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "jedec,lpddr4-channel";
+		io-width = <32>;
+	};
+
 	memory@80000000 {
 		device_type = "memory";
 		reg = <0x0 0x80000000 0x1 0x0>;

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 07/16] arm64: dts: st: add DDR channel to stm32mp257f-ev1 board
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
                   ` (5 preceding siblings ...)
  2025-07-11 14:48 ` [PATCH v2 06/16] arm64: dts: st: add LPDDR channel to stm32mp257f-dk board Clément Le Goffic
@ 2025-07-11 14:48 ` Clément Le Goffic
  2025-07-11 14:49 ` [PATCH v2 08/16] dt-bindings: perf: stm32: introduce DDRPERFM dt-bindings Clément Le Goffic
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:48 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

Add 32bits DDR4 channel to the stm32mp257f-dk board.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp257f-ev1.dts | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
index 2f561ad40665..f987d86d350f 100644
--- a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
+++ b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
@@ -41,6 +41,11 @@ pad_clk: pad-clk {
 		};
 	};
 
+	ddr_channel: ddr4-channel {
+		compatible = "jedec,ddr4-channel";
+		io-width = <32>;
+	};
+
 	imx335_2v9: regulator-2v9 {
 		compatible = "regulator-fixed";
 		regulator-name = "imx335-avdd";

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 08/16] dt-bindings: perf: stm32: introduce DDRPERFM dt-bindings
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
                   ` (6 preceding siblings ...)
  2025-07-11 14:48 ` [PATCH v2 07/16] arm64: dts: st: add DDR channel to stm32mp257f-ev1 board Clément Le Goffic
@ 2025-07-11 14:49 ` Clément Le Goffic
  2025-07-11 14:49 ` [PATCH v2 09/16] perf: stm32: introduce DDRPERFM driver Clément Le Goffic
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:49 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

DDRPERFM is the DDR Performance Monitor embedded in STM32MPU SoC.
It allows to monitor DDR events that come from the DDR Controller
such as read or write events.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
 .../devicetree/bindings/perf/st,stm32-ddr-pmu.yaml | 87 ++++++++++++++++++++++
 1 file changed, 87 insertions(+)

diff --git a/Documentation/devicetree/bindings/perf/st,stm32-ddr-pmu.yaml b/Documentation/devicetree/bindings/perf/st,stm32-ddr-pmu.yaml
new file mode 100644
index 000000000000..3c123a4a0e80
--- /dev/null
+++ b/Documentation/devicetree/bindings/perf/st,stm32-ddr-pmu.yaml
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+maintainers:
+  - Clément Le Goffic <legoffic.clement@gmail.com>
+
+title: STMicroelectronics STM32 DDR Performance Monitor (DDRPERFM)
+
+properties:
+  compatible:
+    enum:
+      - st,stm32mp131-ddr-pmu
+      - st,stm32mp151-ddr-pmu
+      - st,stm32mp251-ddr-pmu
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  access-controllers:
+    minItems: 1
+    maxItems: 2
+
+  memory-channel:
+    description:
+      The memory channel this DDRPERFM is attached to.
+    $ref: /schemas/types.yaml#/definitions/phandle
+
+required:
+  - compatible
+  - reg
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: st,stm32mp131-ddr-pmu
+    then:
+      required:
+        - clocks
+        - resets
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: st,stm32mp251-ddr-pmu
+    then:
+      required:
+        - access-controllers
+        - memory-channel
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    #include <dt-bindings/reset/stm32mp1-resets.h>
+
+    perf@5a007000 {
+        compatible = "st,stm32mp151-ddr-pmu";
+        reg = <0x5a007000 0x400>;
+        clocks = <&rcc DDRPERFM>;
+        resets = <&rcc DDRPERFM_R>;
+    };
+
+  - |
+    ddr_channel: ddr3-channel {
+        compatible = "jedec,ddr3-channel";
+        io-width = <16>;
+    };
+
+    perf@48041000 {
+      compatible = "st,stm32mp251-ddr-pmu";
+      reg = <0x48041000 0x400>;
+      access-controllers = <&rcc 104>;
+      memory-channel = <&ddr_channel>;
+    };

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 09/16] perf: stm32: introduce DDRPERFM driver
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
                   ` (7 preceding siblings ...)
  2025-07-11 14:49 ` [PATCH v2 08/16] dt-bindings: perf: stm32: introduce DDRPERFM dt-bindings Clément Le Goffic
@ 2025-07-11 14:49 ` Clément Le Goffic
  2025-07-11 16:04   ` Jonathan Cameron
  2025-07-14 19:39   ` Dan Carpenter
  2025-07-11 14:49 ` [PATCH v2 10/16] Documentation: perf: stm32: add ddrperfm support Clément Le Goffic
                   ` (7 subsequent siblings)
  16 siblings, 2 replies; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:49 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

Introduce the driver for the DDR Performance Monitor available on
STM32MPU SoC.

On STM32MP2 platforms, the DDRPERFM allows to monitor up to 8 DDR events
that come from the DDR Controller such as read or write events.

On STM32MP1 platforms, the DDRPERFM cannot monitor any event on any
counter, there is a notion of set of events.
Events from different sets cannot be monitored at the same time.
The first chosen event selects the set.
The set is coded in the first two bytes of the config value which is on 4
bytes.

On STM32MP25x series, the DDRPERFM clock is shared with the DDR controller
and may be secured by bootloaders.
Access controllers allow to check access to a resource. Use the access
controller defined in the devicetree to know about the access to the
DDRPERFM clock.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
 drivers/perf/Kconfig         |  11 +
 drivers/perf/Makefile        |   1 +
 drivers/perf/stm32_ddr_pmu.c | 910 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 922 insertions(+)

diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index 278c929dc87a..5118535134ee 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -198,6 +198,17 @@ config QCOM_L3_PMU
 	   Adds the L3 cache PMU into the perf events subsystem for
 	   monitoring L3 cache events.
 
+config STM32_DDR_PMU
+	tristate "STM32 DDR PMU"
+	depends on ARCH_STM32 || COMPILE_TEST
+	default m
+	help
+	  Provides support for the DDR performance monitor on STM32MPU platforms.
+	  The monitor provides counters for memory related events.
+	  It allows developers to analyze and optimize DDR performance.
+	  Enabling this feature is useful for performance tuning and debugging memory
+	  subsystem issues on supported hardware.
+
 config THUNDERX2_PMU
 	tristate "Cavium ThunderX2 SoC PMU UNCORE"
 	depends on ARCH_THUNDER2 || COMPILE_TEST
diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
index de71d2574857..7f83b50feb71 100644
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_RISCV_PMU) += riscv_pmu.o
 obj-$(CONFIG_RISCV_PMU_LEGACY) += riscv_pmu_legacy.o
 obj-$(CONFIG_RISCV_PMU_SBI) += riscv_pmu_sbi.o
 obj-$(CONFIG_STARFIVE_STARLINK_PMU) += starfive_starlink_pmu.o
+obj-$(CONFIG_STM32_DDR_PMU) += stm32_ddr_pmu.o
 obj-$(CONFIG_THUNDERX2_PMU) += thunderx2_pmu.o
 obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o
 obj-$(CONFIG_ARM_SPE_PMU) += arm_spe_pmu.o
diff --git a/drivers/perf/stm32_ddr_pmu.c b/drivers/perf/stm32_ddr_pmu.c
new file mode 100644
index 000000000000..1be5bbe12978
--- /dev/null
+++ b/drivers/perf/stm32_ddr_pmu.c
@@ -0,0 +1,910 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025, STMicroelectronics - All Rights Reserved
+ * Author: Clément Le Goffic <clement.legoffic@foss.st.com> for STMicroelectronics.
+ */
+
+#include <linux/bus/stm32_firewall_device.h>
+#include <linux/clk.h>
+#include <linux/hrtimer.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/perf_event.h>
+#include <linux/reset.h>
+
+#define DRIVER_NAME		"stm32_ddr_pmu"
+
+/*
+ * The PMU is able to freeze all counters and generate an interrupt when there
+ * is a counter overflow. But, relying on this means that we lose all the
+ * events that occur between the freeze and the interrupt handler execution.
+ * So we use a polling mechanism to avoid this lost of information.
+ * The fastest counter can overflow in ~7s @600MHz (that is the maximum DDR
+ * frequency supported on STM32MP257), so we poll in 3.5s intervals to ensure
+ * we don't reach this limit.
+ */
+#define POLL_MS			3500
+
+#define DDRPERFM_CTRL		0x000
+#define DDRPERFM_CFG		0x004
+#define DDRPERFM_STATUS		0x008
+#define DDRPERFM_CLR		0x00C
+#define DDRPERFM_TCNT		0x020
+#define DDRPERFM_EVCNT(X)	(0x030 + 8 * (X))
+
+#define DDRPERFM_MP2_CFG0	0x010
+#define DDRPERFM_MP2_CFG1	0x014
+#define DDRPERFM_MP2_CFG5	0x024
+#define DDRPERFM_MP2_DRAMINF	0x028
+#define DDRPERFM_MP2_EVCNT(X)	(0x040 + 4 * (X))
+#define DDRPERFM_MP2_TCNT	0x060
+#define DDRPERFM_MP2_STATUS	0x080
+
+#define MP1_STATUS_BUSY		BIT(16)
+#define MP2_STATUS_BUSY		BIT(31)
+
+#define CTRL_START		BIT(0)
+#define CTRL_STOP		BIT(1)
+
+#define CFG_SEL_MSK		GENMASK(17, 16)
+#define CFG_SEL_SHIFT		16
+#define CFG_EN_MSK		GENMASK(3, 0)
+
+#define MP1_CLR_CNT		GENMASK(3, 0)
+#define MP1_CLR_TIME		BIT(31)
+#define MP2_CLR_CNT		GENMASK(7, 0)
+#define MP2_CLR_TIME		BIT(8)
+
+/* 4 event counters plus 1 dedicated to time */
+#define MP1_CNT_NB		(4 + 1)
+/* Index of the time dedicated counter */
+#define MP1_TIME_CNT_IDX	4
+
+/* 8 event counters plus 1 dedicated to time */
+#define MP2_CNT_NB		(8 + 1)
+/* Index of the time dedicated counter */
+#define MP2_TIME_CNT_IDX	8
+/* 4 event counters per register */
+#define MP2_CNT_SEL_PER_REG	4
+
+/* Arbitrary value used to identify a time event */
+#define TIME_CNT		64
+
+struct stm32_ddr_pmu_reg {
+	unsigned int reg;
+	u32 mask;
+};
+
+struct stm32_ddr_cnt {
+	int idx;
+	struct perf_event *evt;
+	struct list_head cnt_list;
+};
+
+struct stm32_ddr_pmu_regspec {
+	const struct stm32_ddr_pmu_reg stop;
+	const struct stm32_ddr_pmu_reg start;
+	const struct stm32_ddr_pmu_reg enable;
+	const struct stm32_ddr_pmu_reg status;
+	const struct stm32_ddr_pmu_reg clear_cnt;
+	const struct stm32_ddr_pmu_reg clear_time;
+	const struct stm32_ddr_pmu_reg cfg;
+	const struct stm32_ddr_pmu_reg cfg0;
+	const struct stm32_ddr_pmu_reg cfg1;
+	const struct stm32_ddr_pmu_reg dram_inf;
+	const struct stm32_ddr_pmu_reg counter_time;
+	const struct stm32_ddr_pmu_reg counter_evt[];
+};
+
+struct stm32_ddr_pmu {
+	struct pmu pmu;
+	void __iomem *membase;
+	struct device *dev;
+	struct clk *clk;
+	const struct stm32_ddr_pmu_cfg *cfg;
+	struct hrtimer hrtimer;
+	ktime_t poll_period;
+	int selected_set;
+	u32 dram_type;
+	struct list_head counters[];
+};
+
+struct stm32_ddr_pmu_cfg {
+	const struct stm32_ddr_pmu_regspec *regs;
+	const struct attribute_group **attribute;
+	u32 counters_nb;
+	u32 evt_counters_nb;
+	u32 time_cnt_idx;
+	struct stm32_ddr_cnt * (*get_counter)(struct stm32_ddr_pmu *p, struct perf_event *e);
+};
+
+#define EVENT_NUMBER(group, index)	(((group) << 8) | (index))
+#define GROUP_VALUE(event_number)		((event_number) >> 8)
+#define EVENT_INDEX(event_number)	((event_number) & 0xFF)
+
+/* MP1 ddrperfm events */
+enum stm32_ddr_pmu_events_mp1 {
+	PERF_OP_IS_RD			= EVENT_NUMBER(0, 0),
+	PERF_OP_IS_WR			= EVENT_NUMBER(0, 1),
+	PERF_OP_IS_ACTIVATE		= EVENT_NUMBER(0, 2),
+	CTL_IDLE			= EVENT_NUMBER(0, 3),
+	PERF_HPR_REQ_WITH_NO_CREDIT	= EVENT_NUMBER(1, 0),
+	PERF_LPR_REQ_WITH_NO_CREDIT	= EVENT_NUMBER(1, 1),
+	CACTIVE_DDRC			= EVENT_NUMBER(1, 3),
+	PERF_OP_IS_ENTER_POWERDOWN	= EVENT_NUMBER(2, 0),
+	PERF_OP_IS_REFRESH		= EVENT_NUMBER(2, 1),
+	PERF_SELFRESH_MODE		= EVENT_NUMBER(2, 2),
+	DFI_LP_REQ			= EVENT_NUMBER(2, 3),
+	PERF_HPR_XACT_WHEN_CRITICAL	= EVENT_NUMBER(3, 0),
+	PERF_LPR_XACT_WHEN_CRITICAL	= EVENT_NUMBER(3, 1),
+	PERF_WR_XACT_WHEN_CRITICAL	= EVENT_NUMBER(3, 2),
+	DFI_LP_REQ_SCND			= EVENT_NUMBER(3, 3),
+};
+
+/* MP2 ddrperfm events */
+enum stm32_ddr_pmu_events_mp2 {
+	DFI_IS_ACT			= EVENT_NUMBER(0, 0),
+	DFI_IS_PREPB			= EVENT_NUMBER(0, 1),
+	DFI_IS_PREAB			= EVENT_NUMBER(0, 2),
+	DFI_IS_RD			= EVENT_NUMBER(0, 3),
+	DFI_IS_RDA			= EVENT_NUMBER(0, 4),
+	DFI_IS_WR			= EVENT_NUMBER(0, 6),
+	DFI_IS_WRA			= EVENT_NUMBER(0, 7),
+	DFI_IS_MWR			= EVENT_NUMBER(0, 9),
+	DFI_IS_MWRA			= EVENT_NUMBER(0, 10),
+	DFI_IS_MRW			= EVENT_NUMBER(0, 12),
+	DFI_IS_MRR			= EVENT_NUMBER(0, 13),
+	DFI_IS_REFPB			= EVENT_NUMBER(0, 14),
+	DFI_IS_REFAB			= EVENT_NUMBER(0, 15),
+	DFI_IS_MPC			= EVENT_NUMBER(0, 16),
+	PERF_OP_IS_ACT			= EVENT_NUMBER(0, 32),
+	PERF_OP_IS_RD_MP2		= EVENT_NUMBER(0, 33),
+	PERF_OP_IS_WR_MP2		= EVENT_NUMBER(0, 34),
+	PERF_OP_IS_MWR			= EVENT_NUMBER(0, 35),
+	PERF_OP_IS_REF			= EVENT_NUMBER(0, 36),
+	PERF_OP_IS_CRIT_REF		= EVENT_NUMBER(0, 37),
+	PERF_OP_IS_SPEC_REF		= EVENT_NUMBER(0, 38),
+	PERF_OP_IS_ZQCAL		= EVENT_NUMBER(0, 39),
+	PERF_OP_IS_ENTER_POWDN		= EVENT_NUMBER(0, 40),
+	PERF_OP_IS_ENTER_SELFREF	= EVENT_NUMBER(0, 41),
+	PERF_OP_IS_PRE			= EVENT_NUMBER(0, 42),
+	PERF_OP_IS_PRE_FOR_RDWR		= EVENT_NUMBER(0, 43),
+	PERF_OP_IS_PRE_FOR_OTHERS	= EVENT_NUMBER(0, 44),
+	PERF_OP_IS_RD_ACTIVATE		= EVENT_NUMBER(0, 45),
+	PERF_HPR_REQ_WITH_NOCREDIT	= EVENT_NUMBER(0, 48),
+	PERF_LPR_REQ_WITH_NOCREDIT	= EVENT_NUMBER(0, 49),
+	PERF_HPR_XACT_WHEN_CRITICAL_MP2	= EVENT_NUMBER(0, 50),
+	PERF_LPR_XACT_WHEN_CRITICAL_MP2	= EVENT_NUMBER(0, 51),
+	PERF_WR_XACT_WHEN_CRITICAL_MP2	= EVENT_NUMBER(0, 52),
+	PERF_RDWR_TRANSITIONS		= EVENT_NUMBER(0, 53),
+	PERF_WAR_HAZARD			= EVENT_NUMBER(0, 54),
+	PERF_RAW_HAZARD			= EVENT_NUMBER(0, 55),
+	PERF_WAW_HAZARD			= EVENT_NUMBER(0, 56),
+	PERF_RANK			= EVENT_NUMBER(0, 58),
+	PERF_READ_BYPASS		= EVENT_NUMBER(0, 59),
+	PERF_ACT_BYPASS			= EVENT_NUMBER(0, 60),
+	PERF_WINDOW_LIMIT_REACHED_RD	= EVENT_NUMBER(0, 61),
+	PERF_WINDOW_LIMIT_REACHED_WR	= EVENT_NUMBER(0, 62),
+	NO_EVENT			= EVENT_NUMBER(0, 63),
+};
+
+enum stm32_ddr_pmu_memory_type {
+	STM32_DDR_PMU_LPDDR4,
+	STM32_DDR_PMU_LPDDR3,
+	STM32_DDR_PMU_DDR4,
+	STM32_DDR_PMU_DDR3
+};
+
+static struct stm32_ddr_pmu *to_stm32_ddr_pmu(struct pmu *p)
+{
+	return container_of(p, struct stm32_ddr_pmu, pmu);
+}
+
+static struct stm32_ddr_pmu *hrtimer_to_stm32_ddr_pmu(struct hrtimer *h)
+{
+	return container_of(h, struct stm32_ddr_pmu, hrtimer);
+}
+
+static void stm32_ddr_start_counters(struct stm32_ddr_pmu *pmu)
+{
+	const struct stm32_ddr_pmu_regspec *r = pmu->cfg->regs;
+
+	writel_relaxed(r->start.mask, pmu->membase + r->start.reg);
+}
+
+static void stm32_ddr_stop_counters(struct stm32_ddr_pmu *pmu)
+{
+	const struct stm32_ddr_pmu_regspec *r = pmu->cfg->regs;
+
+	writel_relaxed(r->stop.mask, pmu->membase + r->stop.reg);
+}
+
+static void stm32_ddr_clear_time_counter(struct stm32_ddr_pmu *pmu)
+{
+	const struct stm32_ddr_pmu_regspec *r = pmu->cfg->regs;
+
+	writel_relaxed(r->clear_time.mask, pmu->membase + r->clear_time.reg);
+}
+
+static void stm32_ddr_clear_event_counter(struct stm32_ddr_pmu *pmu, struct stm32_ddr_cnt *counter)
+{
+	const struct stm32_ddr_pmu_regspec *r = pmu->cfg->regs;
+
+	writel_relaxed(r->clear_cnt.mask & BIT(counter->idx), pmu->membase + r->clear_cnt.reg);
+}
+
+static void stm32_ddr_clear_counter(struct stm32_ddr_pmu *pmu, struct stm32_ddr_cnt *counter)
+{
+	const struct stm32_ddr_pmu_regspec *r = pmu->cfg->regs;
+	u32 status = readl_relaxed(pmu->membase + r->status.reg);
+
+	if (counter->idx == pmu->cfg->time_cnt_idx)
+		stm32_ddr_clear_time_counter(pmu);
+	else
+		stm32_ddr_clear_event_counter(pmu, counter);
+
+	if (status & r->status.mask)
+		dev_err(pmu->dev, "Failed to clear counter %i because the PMU is busy\n",
+			counter->idx);
+}
+
+static void stm32_ddr_counter_enable(struct stm32_ddr_pmu *pmu, struct stm32_ddr_cnt *counter)
+{
+	const struct stm32_ddr_pmu_regspec *r = pmu->cfg->regs;
+	u32 val = readl_relaxed(pmu->membase + r->enable.reg);
+
+	val |= BIT(counter->idx);
+	writel_relaxed(val, pmu->membase + r->enable.reg);
+}
+
+static void stm32_ddr_counter_disable(struct stm32_ddr_pmu *pmu, struct stm32_ddr_cnt *counter)
+{
+	const struct stm32_ddr_pmu_regspec *r = pmu->cfg->regs;
+	u32 val = readl_relaxed(pmu->membase + r->enable.reg);
+
+	val &= ~BIT(counter->idx);
+	writel_relaxed(val, pmu->membase + r->enable.reg);
+}
+
+static int stm32_ddr_sel_evnt(struct stm32_ddr_pmu *pmu, struct stm32_ddr_cnt *counter)
+{
+	const struct stm32_ddr_pmu_regspec *r = pmu->cfg->regs;
+	u32 cnt_sel_val;
+
+	u32 group_val = GROUP_VALUE(counter->evt->attr.config);
+	u32 evt_val = EVENT_INDEX(counter->evt->attr.config);
+
+	if (pmu->selected_set != -1 && pmu->selected_set != group_val) {
+		dev_err(pmu->dev, "Selected events are from different set\n");
+		return -EINVAL;
+	}
+	pmu->selected_set = group_val;
+
+	if (pmu->cfg->regs->cfg.reg) {
+		cnt_sel_val = readl_relaxed(pmu->membase + r->cfg.reg);
+		cnt_sel_val &= ~CFG_SEL_MSK;
+		cnt_sel_val |= (CFG_SEL_MSK & (group_val << CFG_SEL_SHIFT));
+		writel_relaxed(cnt_sel_val, pmu->membase + r->cfg.reg);
+
+		return 0;
+	}
+
+	/* We assume cfg0 and cfg1 are filled in the match data */
+	u32 cnt_idx = counter->idx;
+	u32 cnt_sel_evt_reg = r->cfg0.reg;
+
+	if (!(cnt_idx < MP2_CNT_SEL_PER_REG)) {
+		cnt_sel_evt_reg = r->cfg1.reg;
+		cnt_idx -= MP2_CNT_SEL_PER_REG;
+	}
+
+	cnt_sel_val = readl_relaxed(pmu->membase + cnt_sel_evt_reg);
+	cnt_sel_val &= ~GENMASK(8 * cnt_idx + 7, 8 * cnt_idx);
+	cnt_sel_val |= evt_val << (8 * cnt_idx);
+
+	writel_relaxed(cnt_sel_val, pmu->membase + cnt_sel_evt_reg);
+
+	return 0;
+}
+
+static struct stm32_ddr_cnt *stm32_ddr_pmu_get_event_counter_mp1(struct stm32_ddr_pmu *pmu,
+								 struct perf_event *event)
+{
+	u32 config = event->attr.config;
+	u32 event_idx = EVENT_INDEX(config);
+	struct stm32_ddr_cnt *cnt;
+
+	cnt = kzalloc(sizeof(*cnt), GFP_KERNEL);
+	if (!cnt)
+		return ERR_PTR(-ENOMEM);
+
+	cnt->evt = event;
+	cnt->idx = event_idx;
+	event->pmu_private = cnt;
+	list_add(&cnt->cnt_list, &pmu->counters[event_idx]);
+
+	return cnt;
+}
+
+static struct stm32_ddr_cnt *stm32_ddr_pmu_get_event_counter_mp2(struct stm32_ddr_pmu *pmu,
+								 struct perf_event *event)
+{
+	struct stm32_ddr_cnt *cnt;
+	int idx = -1;
+
+	/* Loop on all the counters except TIME_CNT_IDX */
+	for (int i = 0; i < pmu->cfg->evt_counters_nb; i++) {
+		u64 config;
+
+		if (list_empty(&pmu->counters[i])) {
+			idx = i;
+			continue;
+		}
+		config = list_first_entry(&pmu->counters[i], struct stm32_ddr_cnt,
+					  cnt_list)->evt->attr.config;
+		if (config == event->attr.config) {
+			idx = i;
+			break;
+		}
+	}
+
+	if (idx == -1)
+		return ERR_PTR(-ENOENT);
+
+	cnt = kzalloc(sizeof(*cnt), GFP_KERNEL);
+	if (!cnt)
+		return ERR_PTR(-ENOMEM);
+
+	cnt->evt = event;
+	cnt->idx = idx;
+	event->pmu_private = cnt;
+
+	list_add(&cnt->cnt_list, &pmu->counters[idx]);
+
+	return cnt;
+}
+
+static inline struct stm32_ddr_cnt *stm32_get_event_counter(struct stm32_ddr_pmu *pmu,
+							    struct perf_event *event)
+{
+	return pmu->cfg->get_counter(pmu, event);
+}
+
+static int stm32_ddr_pmu_get_counter(struct stm32_ddr_pmu *pmu, struct perf_event *event)
+{
+	u32 time_cnt_idx = pmu->cfg->time_cnt_idx;
+	u32 config = event->attr.config;
+	struct stm32_ddr_cnt *cnt;
+
+	if (!pmu || !event)
+		return -EINVAL;
+
+	pmu->selected_set = GROUP_VALUE(config);
+
+	if (config == TIME_CNT) {
+		cnt = kzalloc(sizeof(*cnt), GFP_KERNEL);
+		if (!cnt)
+			return -ENOMEM;
+
+		cnt->evt = event;
+		cnt->idx = time_cnt_idx;
+		event->pmu_private = cnt;
+		list_add(&cnt->cnt_list, &pmu->counters[time_cnt_idx]);
+
+		return 0;
+	}
+
+	cnt = stm32_get_event_counter(pmu, event);
+	if (IS_ERR(cnt))
+		return PTR_ERR(cnt);
+
+	if (list_count_nodes(&cnt->cnt_list) == 1) {
+		stm32_ddr_stop_counters(pmu);
+		stm32_ddr_sel_evnt(pmu, cnt);
+		stm32_ddr_counter_enable(pmu, cnt);
+		stm32_ddr_start_counters(pmu);
+	}
+
+	return 0;
+}
+
+static void stm32_ddr_pmu_free_counter(struct stm32_ddr_pmu *pmu,
+				       struct stm32_ddr_cnt *counter)
+{
+	size_t count = list_count_nodes(&counter->cnt_list);
+
+	if (counter->evt->attr.config != TIME_CNT && count == 1)
+		stm32_ddr_counter_disable(pmu, counter);
+
+	list_del(&counter->cnt_list);
+	kfree(counter);
+}
+
+static void stm32_ddr_pmu_event_update_list(struct stm32_ddr_pmu *pmu, struct list_head *list)
+{
+	struct stm32_ddr_cnt *counter = list_first_entry(list, struct stm32_ddr_cnt, cnt_list);
+	const struct stm32_ddr_pmu_regspec *r = pmu->cfg->regs;
+	u32 val;
+
+	if (counter->evt->attr.config != TIME_CNT)
+		val = readl_relaxed(pmu->membase + r->counter_evt[counter->idx].reg);
+	else
+		val = readl_relaxed(pmu->membase + r->counter_time.reg);
+
+	stm32_ddr_clear_counter(pmu, counter);
+
+	list_for_each_entry(counter, list, cnt_list)
+		local64_add(val, &counter->evt->count);
+}
+
+static void stm32_ddr_pmu_event_read(struct perf_event *event)
+{
+	struct stm32_ddr_pmu *pmu = to_stm32_ddr_pmu(event->pmu);
+	struct stm32_ddr_cnt *cnt = event->pmu_private;
+
+	hrtimer_start(&pmu->hrtimer, pmu->poll_period, HRTIMER_MODE_REL_PINNED);
+
+	stm32_ddr_stop_counters(pmu);
+
+	stm32_ddr_pmu_event_update_list(pmu, &pmu->counters[cnt->idx]);
+
+	stm32_ddr_start_counters(pmu);
+}
+
+static void stm32_ddr_pmu_event_start(struct perf_event *event, int flags)
+{
+	struct stm32_ddr_pmu *pmu = to_stm32_ddr_pmu(event->pmu);
+	struct stm32_ddr_cnt *counter = event->pmu_private;
+	struct hw_perf_event *hw = &event->hw;
+
+	if (WARN_ON_ONCE(!(hw->state & PERF_HES_STOPPED)))
+		return;
+
+	if (flags & PERF_EF_RELOAD)
+		WARN_ON_ONCE(!(hw->state & PERF_HES_UPTODATE));
+
+	stm32_ddr_stop_counters(pmu);
+
+	if (list_count_nodes(&counter->cnt_list) == 1)
+		stm32_ddr_clear_counter(pmu, counter);
+	else
+		stm32_ddr_pmu_event_update_list(pmu, &pmu->counters[counter->idx]);
+
+	stm32_ddr_start_counters(pmu);
+	local64_set(&hw->prev_count, 0);
+	hw->state = 0;
+}
+
+static void stm32_ddr_pmu_event_stop(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hw = &event->hw;
+
+	if (WARN_ON_ONCE(hw->state & PERF_HES_STOPPED))
+		return;
+
+	hw->state |= PERF_HES_STOPPED;
+
+	if (flags & PERF_EF_UPDATE) {
+		stm32_ddr_pmu_event_read(event);
+		hw->state |= PERF_HES_UPTODATE;
+	}
+}
+
+static int stm32_ddr_pmu_event_add(struct perf_event *event, int flags)
+{
+	struct stm32_ddr_pmu *pmu = to_stm32_ddr_pmu(event->pmu);
+	int ret;
+
+	clk_enable(pmu->clk);
+
+	hrtimer_start(&pmu->hrtimer, pmu->poll_period, HRTIMER_MODE_REL_PINNED);
+
+	ret = stm32_ddr_pmu_get_counter(pmu, event);
+	if (ret)
+		return ret;
+
+	event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+
+	if (flags & PERF_EF_START)
+		stm32_ddr_pmu_event_start(event, flags);
+
+	return 0;
+}
+
+static void stm32_ddr_pmu_event_del(struct perf_event *event, int flags)
+{
+	struct stm32_ddr_pmu *pmu = to_stm32_ddr_pmu(event->pmu);
+	struct stm32_ddr_cnt *counter = event->pmu_private;
+	bool events = true;
+
+	stm32_ddr_pmu_event_stop(event, PERF_EF_UPDATE);
+
+	stm32_ddr_pmu_free_counter(pmu, counter);
+
+	for (int i = 0; i < pmu->cfg->counters_nb; i++)
+		events = !list_empty(&pmu->counters[i]);
+
+	/* If there is activity nothing to do */
+	if (events)
+		return;
+
+	hrtimer_cancel(&pmu->hrtimer);
+	stm32_ddr_stop_counters(pmu);
+
+	pmu->selected_set = -1;
+
+	clk_disable(pmu->clk);
+}
+
+static int stm32_ddr_pmu_event_init(struct perf_event *event)
+{
+	if (event->attr.type != event->pmu->type)
+		return -ENOENT;
+
+	if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+		return -EINVAL;
+
+	return 0;
+}
+
+static enum hrtimer_restart stm32_ddr_pmu_poll(struct hrtimer *hrtimer)
+{
+	struct stm32_ddr_pmu *pmu = hrtimer_to_stm32_ddr_pmu(hrtimer);
+
+	stm32_ddr_stop_counters(pmu);
+
+	for (int i = 0; i < MP2_CNT_NB; i++)
+		if (!list_empty(&pmu->counters[i]))
+			stm32_ddr_pmu_event_update_list(pmu, &pmu->counters[i]);
+
+	if (list_empty(&pmu->counters[pmu->cfg->time_cnt_idx]))
+		stm32_ddr_clear_time_counter(pmu);
+
+	stm32_ddr_start_counters(pmu);
+
+	hrtimer_forward_now(hrtimer, pmu->poll_period);
+
+	return HRTIMER_RESTART;
+}
+
+static ssize_t stm32_ddr_pmu_sysfs_show(struct device *dev, struct device_attribute *attr,
+					char *buf)
+{
+	struct perf_pmu_events_attr *pmu_attr;
+
+	pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr);
+
+	return sysfs_emit(buf, "event=0x%02llx\n", pmu_attr->id);
+}
+
+static int stm32_ddr_pmu_get_memory_type(struct stm32_ddr_pmu *pmu)
+{
+	struct platform_device *pdev = to_platform_device(pmu->dev);
+	struct device_node *memchan;
+
+	memchan = of_parse_phandle(pdev->dev.of_node, "memory-channel", 0);
+	if (!memchan)
+		return dev_err_probe(&pdev->dev, -EINVAL,
+				     "Missing device-tree property 'memory-channel'\n");
+
+	if (of_device_is_compatible(memchan, "jedec,lpddr4-channel"))
+		pmu->dram_type = STM32_DDR_PMU_LPDDR4;
+	else if (of_device_is_compatible(memchan, "jedec,lpddr3-channel"))
+		pmu->dram_type = STM32_DDR_PMU_LPDDR3;
+	else if (of_device_is_compatible(memchan, "jedec,ddr4-channel"))
+		pmu->dram_type = STM32_DDR_PMU_DDR4;
+	else if (of_device_is_compatible(memchan, "jedec,ddr3-channel"))
+		pmu->dram_type = STM32_DDR_PMU_DDR3;
+	else
+		return dev_err_probe(&pdev->dev, -EINVAL, "Unsupported memory channel type\n");
+
+	if (pmu->dram_type == STM32_DDR_PMU_LPDDR3)
+		dev_warn(&pdev->dev,
+			 "LPDDR3 supported by DDRPERFM but not supported by DDRCTRL/DDRPHY\n");
+
+	return 0;
+}
+
+#define STM32_DDR_PMU_EVENT_ATTR(_name, _id)			\
+	PMU_EVENT_ATTR_ID(_name, stm32_ddr_pmu_sysfs_show, _id)
+
+static struct attribute *stm32_ddr_pmu_events_attrs_mp[] = {
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_rd, PERF_OP_IS_RD),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_wr, PERF_OP_IS_WR),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_activate, PERF_OP_IS_ACTIVATE),
+	STM32_DDR_PMU_EVENT_ATTR(ctl_idle, CTL_IDLE),
+	STM32_DDR_PMU_EVENT_ATTR(perf_hpr_req_with_no_credit, PERF_HPR_REQ_WITH_NO_CREDIT),
+	STM32_DDR_PMU_EVENT_ATTR(perf_lpr_req_with_no_credit, PERF_LPR_REQ_WITH_NO_CREDIT),
+	STM32_DDR_PMU_EVENT_ATTR(cactive_ddrc, CACTIVE_DDRC),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_enter_powerdown, PERF_OP_IS_ENTER_POWERDOWN),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_refresh, PERF_OP_IS_REFRESH),
+	STM32_DDR_PMU_EVENT_ATTR(perf_selfresh_mode, PERF_SELFRESH_MODE),
+	STM32_DDR_PMU_EVENT_ATTR(dfi_lp_req, DFI_LP_REQ),
+	STM32_DDR_PMU_EVENT_ATTR(perf_hpr_xact_when_critical, PERF_HPR_XACT_WHEN_CRITICAL),
+	STM32_DDR_PMU_EVENT_ATTR(perf_lpr_xact_when_critical, PERF_LPR_XACT_WHEN_CRITICAL),
+	STM32_DDR_PMU_EVENT_ATTR(perf_wr_xact_when_critical, PERF_WR_XACT_WHEN_CRITICAL),
+	STM32_DDR_PMU_EVENT_ATTR(dfi_lp_req_cpy, DFI_LP_REQ),  /* Suffixed '_cpy' to allow the
+								* choice between sets 2 and 3
+								*/
+	STM32_DDR_PMU_EVENT_ATTR(time_cnt, TIME_CNT),
+	NULL,
+};
+
+static struct attribute_group stm32_ddr_pmu_events_attrs_group_mp = {
+	.name = "events",
+	.attrs = stm32_ddr_pmu_events_attrs_mp,
+};
+
+static struct attribute *stm32_ddr_pmu_events_attrs_mp2[] = {
+	STM32_DDR_PMU_EVENT_ATTR(dfi_is_act, DFI_IS_ACT),
+	STM32_DDR_PMU_EVENT_ATTR(dfi_is_prepb, DFI_IS_PREPB),
+	STM32_DDR_PMU_EVENT_ATTR(dfi_is_preab, DFI_IS_PREAB),
+	STM32_DDR_PMU_EVENT_ATTR(dfi_is_rd, DFI_IS_RD),
+	STM32_DDR_PMU_EVENT_ATTR(dfi_is_rda, DFI_IS_RDA),
+	STM32_DDR_PMU_EVENT_ATTR(dfi_is_wr, DFI_IS_WR),
+	STM32_DDR_PMU_EVENT_ATTR(dfi_is_wra, DFI_IS_WRA),
+	STM32_DDR_PMU_EVENT_ATTR(dfi_is_mwr, DFI_IS_MWR),
+	STM32_DDR_PMU_EVENT_ATTR(dfi_is_mwra, DFI_IS_MWRA),
+	STM32_DDR_PMU_EVENT_ATTR(dfi_is_mrw, DFI_IS_MRW),
+	STM32_DDR_PMU_EVENT_ATTR(dfi_is_mrr, DFI_IS_MRR),
+	STM32_DDR_PMU_EVENT_ATTR(dfi_is_refpb, DFI_IS_REFPB),
+	STM32_DDR_PMU_EVENT_ATTR(dfi_is_refab, DFI_IS_REFAB),
+	STM32_DDR_PMU_EVENT_ATTR(dfi_is_mpc, DFI_IS_MPC),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_act, PERF_OP_IS_ACT),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_rd, PERF_OP_IS_RD),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_wr, PERF_OP_IS_WR),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_mwr, PERF_OP_IS_MWR),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_ref, PERF_OP_IS_REF),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_crit_ref, PERF_OP_IS_CRIT_REF),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_spec_ref, PERF_OP_IS_SPEC_REF),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_zqcal, PERF_OP_IS_ZQCAL),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_enter_powdn, PERF_OP_IS_ENTER_POWDN),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_enter_selfref, PERF_OP_IS_ENTER_SELFREF),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_pre, PERF_OP_IS_PRE),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_pre_for_rdwr, PERF_OP_IS_PRE_FOR_RDWR),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_pre_for_others, PERF_OP_IS_PRE_FOR_OTHERS),
+	STM32_DDR_PMU_EVENT_ATTR(perf_op_is_rd_activate, PERF_OP_IS_RD_ACTIVATE),
+	STM32_DDR_PMU_EVENT_ATTR(perf_hpr_req_with_nocredit, PERF_HPR_REQ_WITH_NOCREDIT),
+	STM32_DDR_PMU_EVENT_ATTR(perf_lpr_req_with_nocredit, PERF_LPR_REQ_WITH_NOCREDIT),
+	STM32_DDR_PMU_EVENT_ATTR(perf_hpr_xact_when_critical, PERF_HPR_XACT_WHEN_CRITICAL),
+	STM32_DDR_PMU_EVENT_ATTR(perf_lpr_xact_when_critical, PERF_LPR_XACT_WHEN_CRITICAL),
+	STM32_DDR_PMU_EVENT_ATTR(perf_wr_xact_when_critical, PERF_WR_XACT_WHEN_CRITICAL),
+	STM32_DDR_PMU_EVENT_ATTR(perf_rdwr_transitions, PERF_RDWR_TRANSITIONS),
+	STM32_DDR_PMU_EVENT_ATTR(perf_war_hazard, PERF_WAR_HAZARD),
+	STM32_DDR_PMU_EVENT_ATTR(perf_raw_hazard, PERF_RAW_HAZARD),
+	STM32_DDR_PMU_EVENT_ATTR(perf_waw_hazard, PERF_WAW_HAZARD),
+	STM32_DDR_PMU_EVENT_ATTR(perf_rank, PERF_RANK),
+	STM32_DDR_PMU_EVENT_ATTR(perf_read_bypass, PERF_READ_BYPASS),
+	STM32_DDR_PMU_EVENT_ATTR(perf_act_bypass, PERF_ACT_BYPASS),
+	STM32_DDR_PMU_EVENT_ATTR(perf_window_limit_reached_rd, PERF_WINDOW_LIMIT_REACHED_RD),
+	STM32_DDR_PMU_EVENT_ATTR(perf_window_limit_reached_wr, PERF_WINDOW_LIMIT_REACHED_WR),
+	STM32_DDR_PMU_EVENT_ATTR(time_cnt, TIME_CNT),
+	NULL
+};
+
+static struct attribute_group stm32_ddr_pmu_events_attrs_group_mp2 = {
+	.name = "events",
+	.attrs = stm32_ddr_pmu_events_attrs_mp2,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-8");
+
+static struct attribute *stm32_ddr_pmu_format_attrs[] = {
+	&format_attr_event.attr,
+	NULL,
+};
+
+static const struct attribute_group stm32_ddr_pmu_format_attr_group = {
+	.name = "format",
+	.attrs = stm32_ddr_pmu_format_attrs,
+};
+
+static const struct attribute_group *stm32_ddr_pmu_attr_groups_mp1[] = {
+	&stm32_ddr_pmu_events_attrs_group_mp,
+	&stm32_ddr_pmu_format_attr_group,
+	NULL,
+};
+
+static const struct attribute_group *stm32_ddr_pmu_attr_groups_mp2[] = {
+	&stm32_ddr_pmu_events_attrs_group_mp2,
+	&stm32_ddr_pmu_format_attr_group,
+	NULL,
+};
+
+static int stm32_ddr_pmu_device_probe(struct platform_device *pdev)
+{
+	struct stm32_firewall firewall;
+	struct stm32_ddr_pmu *pmu;
+	struct reset_control *rst;
+	struct resource *res;
+	int ret;
+
+	pmu = devm_kzalloc(&pdev->dev, struct_size(pmu, counters, MP2_CNT_NB), GFP_KERNEL);
+	if (!pmu)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, pmu);
+	pmu->dev = &pdev->dev;
+
+	pmu->cfg = device_get_match_data(&pdev->dev);
+
+	pmu->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+	if (IS_ERR(pmu->membase))
+		return PTR_ERR(pmu->membase);
+
+	if (of_property_present(pmu->dev->of_node, "access-controllers")) {
+		ret = stm32_firewall_get_firewall(pmu->dev->of_node, &firewall, 1);
+		if (ret)
+			return dev_err_probe(pmu->dev, ret, "Failed to get firewall\n");
+		ret = stm32_firewall_grant_access_by_id(&firewall, firewall.firewall_id);
+		if (ret)
+			return dev_err_probe(pmu->dev, ret, "Failed to grant access\n");
+	}
+
+	pmu->clk = devm_clk_get_optional_prepared(pmu->dev, NULL);
+	if (IS_ERR(pmu->clk))
+		return dev_err_probe(pmu->dev, PTR_ERR(pmu->clk), "Failed to get prepare clock\n");
+
+	clk_enable(pmu->clk);
+
+	rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
+	if (IS_ERR(rst)) {
+		clk_disable_unprepare(pmu->clk);
+		return dev_err_probe(&pdev->dev, PTR_ERR(rst), "Failed to get reset\n");
+	}
+
+	reset_control_assert(rst);
+	reset_control_deassert(rst);
+
+	pmu->poll_period = ms_to_ktime(POLL_MS);
+	hrtimer_setup(&pmu->hrtimer, stm32_ddr_pmu_poll, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+
+	for (int i = 0; i < MP2_CNT_NB; i++)
+		INIT_LIST_HEAD(&pmu->counters[i]);
+
+	pmu->selected_set = -1;
+
+	pmu->pmu = (struct pmu) {
+		.task_ctx_nr = perf_invalid_context,
+		.start = stm32_ddr_pmu_event_start,
+		.stop = stm32_ddr_pmu_event_stop,
+		.add = stm32_ddr_pmu_event_add,
+		.del = stm32_ddr_pmu_event_del,
+		.read = stm32_ddr_pmu_event_read,
+		.event_init = stm32_ddr_pmu_event_init,
+		.attr_groups = pmu->cfg->attribute,
+		.module = THIS_MODULE,
+	};
+
+	ret = perf_pmu_register(&pmu->pmu, DRIVER_NAME, -1);
+	if (ret) {
+		clk_disable_unprepare(pmu->clk);
+		return dev_err_probe(&pdev->dev, ret,
+				     "Couldn't register DDRPERFM driver as a PMU\n");
+	}
+
+	if (pmu->cfg->regs->dram_inf.reg) {
+		ret = stm32_ddr_pmu_get_memory_type(pmu);
+		if (ret) {
+			perf_pmu_unregister(&pmu->pmu);
+			clk_disable_unprepare(pmu->clk);
+			return dev_err_probe(&pdev->dev, ret, "Failed to get memory type\n");
+		}
+
+		writel_relaxed(pmu->dram_type, pmu->membase + pmu->cfg->regs->dram_inf.reg);
+	}
+
+	clk_disable(pmu->clk);
+
+	return 0;
+}
+
+static void stm32_ddr_pmu_device_remove(struct platform_device *pdev)
+{
+	struct stm32_ddr_pmu *stm32_ddr_pmu = platform_get_drvdata(pdev);
+
+	perf_pmu_unregister(&stm32_ddr_pmu->pmu);
+}
+
+static int __maybe_unused stm32_ddr_pmu_device_resume(struct device *dev)
+{
+	struct stm32_ddr_pmu *pmu = dev_get_drvdata(dev);
+
+	clk_enable(pmu->clk);
+	writel_relaxed(pmu->dram_type, pmu->membase + pmu->cfg->regs->dram_inf.reg);
+	clk_disable(pmu->clk);
+
+	return 0;
+}
+
+static const struct stm32_ddr_pmu_regspec stm32_ddr_pmu_regspec_mp1 = {
+	.stop =		{ DDRPERFM_CTRL, CTRL_STOP },
+	.start =	{ DDRPERFM_CTRL, CTRL_START },
+	.enable =	{ DDRPERFM_CFG },
+	.cfg =		{ DDRPERFM_CFG },
+	.status =	{ DDRPERFM_STATUS, MP1_STATUS_BUSY },
+	.clear_cnt =	{ DDRPERFM_CLR, MP1_CLR_CNT},
+	.clear_time =	{ DDRPERFM_CLR, MP1_CLR_TIME},
+	.counter_time =	{ DDRPERFM_TCNT },
+	.counter_evt =	{
+				{ DDRPERFM_EVCNT(0) },
+				{ DDRPERFM_EVCNT(1) },
+				{ DDRPERFM_EVCNT(2) },
+				{ DDRPERFM_EVCNT(3) },
+	},
+};
+
+static const struct stm32_ddr_pmu_regspec stm32_ddr_pmu_regspec_mp2 = {
+	.stop =		{ DDRPERFM_CTRL, CTRL_STOP },
+	.start =	{ DDRPERFM_CTRL, CTRL_START },
+	.status =	{ DDRPERFM_MP2_STATUS, MP2_STATUS_BUSY },
+	.clear_cnt =	{ DDRPERFM_CLR, MP2_CLR_CNT},
+	.clear_time =	{ DDRPERFM_CLR, MP2_CLR_TIME},
+	.cfg0 =		{ DDRPERFM_MP2_CFG0 },
+	.cfg1 =		{ DDRPERFM_MP2_CFG1 },
+	.enable =	{ DDRPERFM_MP2_CFG5 },
+	.dram_inf =	{ DDRPERFM_MP2_DRAMINF },
+	.counter_time =	{ DDRPERFM_MP2_TCNT },
+	.counter_evt =	{
+				{ DDRPERFM_MP2_EVCNT(0) },
+				{ DDRPERFM_MP2_EVCNT(1) },
+				{ DDRPERFM_MP2_EVCNT(2) },
+				{ DDRPERFM_MP2_EVCNT(3) },
+				{ DDRPERFM_MP2_EVCNT(4) },
+				{ DDRPERFM_MP2_EVCNT(5) },
+				{ DDRPERFM_MP2_EVCNT(6) },
+				{ DDRPERFM_MP2_EVCNT(7) },
+	},
+};
+
+static const struct stm32_ddr_pmu_cfg stm32_ddr_pmu_cfg_mp1 = {
+	.regs = &stm32_ddr_pmu_regspec_mp1,
+	.attribute = stm32_ddr_pmu_attr_groups_mp1,
+	.counters_nb = MP1_CNT_NB,
+	.evt_counters_nb = MP1_CNT_NB - 1, /* Time counter is not an event counter */
+	.time_cnt_idx = MP1_TIME_CNT_IDX,
+	.get_counter = stm32_ddr_pmu_get_event_counter_mp1,
+};
+
+static const struct stm32_ddr_pmu_cfg stm32_ddr_pmu_cfg_mp2 = {
+	.regs = &stm32_ddr_pmu_regspec_mp2,
+	.attribute = stm32_ddr_pmu_attr_groups_mp2,
+	.counters_nb = MP2_CNT_NB,
+	.evt_counters_nb = MP2_CNT_NB - 1, /* Time counter is an event counter */
+	.time_cnt_idx = MP2_TIME_CNT_IDX,
+	.get_counter = stm32_ddr_pmu_get_event_counter_mp2,
+};
+
+static const struct dev_pm_ops stm32_ddr_pmu_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(NULL, stm32_ddr_pmu_device_resume)
+};
+
+static const struct of_device_id stm32_ddr_pmu_of_match[] = {
+	{
+		.compatible = "st,stm32mp131-ddr-pmu",
+		.data = &stm32_ddr_pmu_cfg_mp1
+	},
+	{
+		.compatible = "st,stm32mp251-ddr-pmu",
+		.data = &stm32_ddr_pmu_cfg_mp2
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, stm32_ddr_pmu_of_match);
+
+static struct platform_driver stm32_ddr_pmu_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.pm = pm_sleep_ptr(&stm32_ddr_pmu_pm_ops),
+		.of_match_table = stm32_ddr_pmu_of_match,
+	},
+	.probe = stm32_ddr_pmu_device_probe,
+	.remove = stm32_ddr_pmu_device_remove,
+};
+
+module_platform_driver(stm32_ddr_pmu_driver);
+
+MODULE_AUTHOR("Clément Le Goffic");
+MODULE_DESCRIPTION("STMicroelectronics STM32 DDR performance monitor driver");
+MODULE_LICENSE("GPL");

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 10/16] Documentation: perf: stm32: add ddrperfm support
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
                   ` (8 preceding siblings ...)
  2025-07-11 14:49 ` [PATCH v2 09/16] perf: stm32: introduce DDRPERFM driver Clément Le Goffic
@ 2025-07-11 14:49 ` Clément Le Goffic
  2025-07-11 14:49 ` [PATCH v2 11/16] MAINTAINERS: add myself as STM32 DDR PMU maintainer Clément Le Goffic
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:49 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

The DDRPERFM is the DDR Performance Monitor embedded in STM32MPU SoC.

This documentation introduces the DDRPERFM, the stm32-ddr-pmu driver
supporting it and how to use it with the perf tool.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
 Documentation/admin-guide/perf/index.rst         |  1 +
 Documentation/admin-guide/perf/stm32-ddr-pmu.rst | 86 ++++++++++++++++++++++++
 2 files changed, 87 insertions(+)

diff --git a/Documentation/admin-guide/perf/index.rst b/Documentation/admin-guide/perf/index.rst
index 072b510385c4..33aedc4ee5c3 100644
--- a/Documentation/admin-guide/perf/index.rst
+++ b/Documentation/admin-guide/perf/index.rst
@@ -29,3 +29,4 @@ Performance monitor support
    cxl
    ampere_cspmu
    mrvl-pem-pmu
+   stm32-ddr-pmu
diff --git a/Documentation/admin-guide/perf/stm32-ddr-pmu.rst b/Documentation/admin-guide/perf/stm32-ddr-pmu.rst
new file mode 100644
index 000000000000..5b02bf44dd7a
--- /dev/null
+++ b/Documentation/admin-guide/perf/stm32-ddr-pmu.rst
@@ -0,0 +1,86 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+========================================
+STM32 DDR Performance Monitor (DDRPERFM)
+========================================
+
+The DDRPERFM is the DDR Performance Monitor embedded in STM32MPU SoC.
+The DDR controller provides events to DDRPERFM, once selected they are counted in the DDRPERFM
+peripheral.
+
+In MP1 family, the DDRPERFM is able to count 4 different events at the same time.
+However, the 4 events must belong to the same set.
+One hardware counter is dedicated to the time counter, `time_cnt`.
+
+In MP2 family, the DDRPERFM is able to select between 44 different DDR events.
+As for MP1, there is a dedicated hardware counter for the time.
+It is incremented every 4 DDR clock cycles.
+All the other counters can be freely allocated to count any other DDR event.
+
+The stm32-ddr-pmu driver relies on the perf PMU framework to expose the counters via sysfs:
+
+On MP1:
+
+    .. code-block:: bash
+
+        $ ls /sys/bus/event_source/devices/stm32_ddr_pmu/events/
+        cactive_ddrc                 perf_lpr_req_with_no_credit  perf_op_is_wr
+        ctl_idle                     perf_lpr_xact_when_critical  perf_selfresh_mode
+        dfi_lp_req                   perf_op_is_activate          perf_wr_xact_when_critical
+        dfi_lp_req_cpy               perf_op_is_enter_powerdown   time_cnt
+        perf_hpr_req_with_no_credit  perf_op_is_rd
+        perf_hpr_xact_when_critical  perf_op_is_refresh
+
+On MP2:
+
+    .. code-block:: bash
+
+        $ ls /sys/bus/event_source/devices/stm32_ddr_pmu/events/
+        dfi_is_act       perf_hpr_req_with_nocredit   perf_op_is_spec_ref
+        dfi_is_mpc       perf_hpr_xact_when_critical  perf_op_is_wr
+        dfi_is_mrr       perf_lpr_req_with_nocredit   perf_op_is_zqcal
+        dfi_is_mrw       perf_lpr_xact_when_critical  perf_rank
+        dfi_is_mwr       perf_op_is_act               perf_raw_hazard
+        dfi_is_mwra      perf_op_is_crit_ref          perf_rdwr_transitions
+        dfi_is_preab     perf_op_is_enter_powdn       perf_read_bypass
+        dfi_is_prepb     perf_op_is_enter_selfref     perf_war_hazard
+        dfi_is_rd        perf_op_is_mwr               perf_waw_hazard
+        dfi_is_rda       perf_op_is_pre               perf_window_limit_reached_rd
+        dfi_is_refab     perf_op_is_pre_for_others    perf_window_limit_reached_wr
+        dfi_is_refpb     perf_op_is_pre_for_rdwr      perf_wr_xact_when_critical
+        dfi_is_wr        perf_op_is_rd                time_cnt
+        dfi_is_wra       perf_op_is_rd_activate
+        perf_act_bypass  perf_op_is_ref
+
+
+The perf PMU framework is usually invoked via the 'perf stat' tool.
+
+
+Example:
+
+    .. code-block:: bash
+
+        $ perf stat --timeout 60000 -e stm32_ddr_pmu/dfi_is_act/,\
+        > stm32_ddr_pmu/dfi_is_rd/,\
+        > stm32_ddr_pmu/dfi_is_wr/,\
+        > stm32_ddr_pmu/dfi_is_refab/,\
+        > stm32_ddr_pmu/dfi_is_mrw/,\
+        > stm32_ddr_pmu/dfi_is_rda/,\
+        > stm32_ddr_pmu/dfi_is_wra/,\
+        > stm32_ddr_pmu/dfi_is_mrr/,\
+        > stm32_ddr_pmu/time_cnt/ \
+        > -a sleep 5
+
+         Performance counter stats for 'system wide':
+
+                    481025      stm32_ddr_pmu/dfi_is_act/
+                    732166      stm32_ddr_pmu/dfi_is_rd/
+                    144926      stm32_ddr_pmu/dfi_is_wr/
+                    644154      stm32_ddr_pmu/dfi_is_refab/
+                         0      stm32_ddr_pmu/dfi_is_mrw/
+                         0      stm32_ddr_pmu/dfi_is_rda/
+                         0      stm32_ddr_pmu/dfi_is_wra/
+                         0      stm32_ddr_pmu/dfi_is_mrr/
+                 752347686      stm32_ddr_pmu/time_cnt/
+
+               5.014910750 seconds time elapsed

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 11/16] MAINTAINERS: add myself as STM32 DDR PMU maintainer
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
                   ` (9 preceding siblings ...)
  2025-07-11 14:49 ` [PATCH v2 10/16] Documentation: perf: stm32: add ddrperfm support Clément Le Goffic
@ 2025-07-11 14:49 ` Clément Le Goffic
  2025-07-11 14:49 ` [PATCH v2 12/16] ARM: dts: stm32: add ddrperfm on stm32mp131 Clément Le Goffic
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:49 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

Add Clément Le Goffic as STM32 DDR PMU maintainer.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
 MAINTAINERS | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index fad6cb025a19..b721d1758db8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23491,6 +23491,13 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/power/supply/st,stc3117.yaml
 F:	drivers/power/supply/stc3117_fuel_gauge.c
 
+ST STM32 DDR PMU
+M:	Clément Le Goffic <legoffic.clement@gmail.com>
+S:	Maintained
+F:	Documentation/admin-guide/perf/stm32-ddr-pmu.rst
+F:	Documentation/devicetree/bindings/perf/st,stm32-ddr-pmu.yaml
+F:	drivers/perf/stm32_ddr-pmu.c
+
 ST STM32 FIREWALL
 M:	Gatien Chevallier <gatien.chevallier@foss.st.com>
 S:	Maintained

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 12/16] ARM: dts: stm32: add ddrperfm on stm32mp131
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
                   ` (10 preceding siblings ...)
  2025-07-11 14:49 ` [PATCH v2 11/16] MAINTAINERS: add myself as STM32 DDR PMU maintainer Clément Le Goffic
@ 2025-07-11 14:49 ` Clément Le Goffic
  2025-07-11 14:49 ` [PATCH v2 13/16] ARM: dts: stm32: add ddrperfm on stm32mp151 Clément Le Goffic
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:49 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

The DDRPERFM is the DDR Performance Monitor embedded in STM32MP131 SoC.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
 arch/arm/boot/dts/st/stm32mp131.dtsi | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm/boot/dts/st/stm32mp131.dtsi b/arch/arm/boot/dts/st/stm32mp131.dtsi
index 492bcf586361..e097723789aa 100644
--- a/arch/arm/boot/dts/st/stm32mp131.dtsi
+++ b/arch/arm/boot/dts/st/stm32mp131.dtsi
@@ -998,6 +998,13 @@ iwdg2: watchdog@5a002000 {
 			status = "disabled";
 		};
 
+		ddrperfm: perf@5a007000 {
+			compatible = "st,stm32mp131-ddr-pmu";
+			reg = <0x5a007000 0x400>;
+			clocks = <&rcc DDRPERFM>;
+			resets = <&rcc DDRPERFM_R>;
+		};
+
 		rtc: rtc@5c004000 {
 			compatible = "st,stm32mp1-rtc";
 			reg = <0x5c004000 0x400>;

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 13/16] ARM: dts: stm32: add ddrperfm on stm32mp151
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
                   ` (11 preceding siblings ...)
  2025-07-11 14:49 ` [PATCH v2 12/16] ARM: dts: stm32: add ddrperfm on stm32mp131 Clément Le Goffic
@ 2025-07-11 14:49 ` Clément Le Goffic
  2025-07-11 14:49 ` [PATCH v2 14/16] arm64: dts: st: add ddrperfm on stm32mp251 Clément Le Goffic
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:49 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

The DDRPERFM is the DDR Performance Monitor embedded in STM32MP151 SoC.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
 arch/arm/boot/dts/st/stm32mp151.dtsi | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm/boot/dts/st/stm32mp151.dtsi b/arch/arm/boot/dts/st/stm32mp151.dtsi
index 0daa8ffe2ff5..e121de52a054 100644
--- a/arch/arm/boot/dts/st/stm32mp151.dtsi
+++ b/arch/arm/boot/dts/st/stm32mp151.dtsi
@@ -383,6 +383,13 @@ usbphyc_port1: usb-phy@1 {
 			};
 		};
 
+		ddrperfm: perf@5a007000 {
+			compatible = "st,stm32mp151-ddr-pmu", "st,stm32mp131-ddr-pmu";
+			reg = <0x5a007000 0x400>;
+			clocks = <&rcc DDRPERFM>;
+			resets = <&rcc DDRPERFM_R>;
+		};
+
 		rtc: rtc@5c004000 {
 			compatible = "st,stm32mp1-rtc";
 			reg = <0x5c004000 0x400>;

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 14/16] arm64: dts: st: add ddrperfm on stm32mp251
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
                   ` (12 preceding siblings ...)
  2025-07-11 14:49 ` [PATCH v2 13/16] ARM: dts: stm32: add ddrperfm on stm32mp151 Clément Le Goffic
@ 2025-07-11 14:49 ` Clément Le Goffic
  2025-07-11 14:49 ` [PATCH v2 15/16] arm64: dts: st: support ddrperfm on stm32mp257f-dk Clément Le Goffic
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:49 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

The DDRPERFM is the DDR Performance Monitor embedded in STM32MP251 SoC.

Keep the node disabled at SoC level as it requires the property
`st,dram-type` which is provided in board dtsi file.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp251.dtsi | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
index 0683c2d5cb6f..7f138324610a 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -1577,5 +1577,12 @@ exti2: interrupt-controller@46230000 {
 				<0>,
 				<&intc GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>;	/* EXTI_70 */
 		};
+
+		ddrperfm: perf@48041000 {
+			compatible = "st,stm32mp251-ddr-pmu";
+			reg = <0x48041000 0x400>;
+			access-controllers = <&rcc 104>;
+			status = "disabled";
+		};
 	};
 };

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 15/16] arm64: dts: st: support ddrperfm on stm32mp257f-dk
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
                   ` (13 preceding siblings ...)
  2025-07-11 14:49 ` [PATCH v2 14/16] arm64: dts: st: add ddrperfm on stm32mp251 Clément Le Goffic
@ 2025-07-11 14:49 ` Clément Le Goffic
  2025-07-11 14:49 ` [PATCH v2 16/16] arm64: dts: st: support ddrperfm on stm32mp257f-ev1 Clément Le Goffic
  2025-07-14 15:24 ` [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Rob Herring (Arm)
  16 siblings, 0 replies; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:49 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

Configure DDRPERFM node on stm32mp257f-dk board.
Disable the node as DDRPERFM will produce an error message if it's clock
(shared with the DDRCTRL on STM32MP25x) is secured by common bootloaders.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp257f-dk.dts | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp257f-dk.dts b/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
index a97b41f14ecc..d236ebf2bb10 100644
--- a/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
+++ b/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
@@ -84,6 +84,11 @@ &arm_wdt {
 	status = "okay";
 };
 
+&ddrperfm {
+	memory-channel = <&lpddr_channel>;
+	status = "disabled";
+};
+
 &scmi_regu {
 	scmi_vddio1: regulator@0 {
 		regulator-min-microvolt = <1800000>;

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 16/16] arm64: dts: st: support ddrperfm on stm32mp257f-ev1
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
                   ` (14 preceding siblings ...)
  2025-07-11 14:49 ` [PATCH v2 15/16] arm64: dts: st: support ddrperfm on stm32mp257f-dk Clément Le Goffic
@ 2025-07-11 14:49 ` Clément Le Goffic
  2025-07-14 15:24 ` [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Rob Herring (Arm)
  16 siblings, 0 replies; 32+ messages in thread
From: Clément Le Goffic @ 2025-07-11 14:49 UTC (permalink / raw)
  To: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic
  Cc: linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk, Clément Le Goffic

Configure DDRPERFM node on stm32mp257f-ev1 board.
Disable the node as DDRPERFM will produce an error message if it's clock
(shared with the DDRCTRL on STM32MP25x) is secured by common bootloaders.

Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp257f-ev1.dts | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
index f987d86d350f..7533b500135c 100644
--- a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
+++ b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
@@ -128,6 +128,11 @@ csi_source: endpoint {
 	};
 };
 
+&ddrperfm {
+	memory-channel = <&ddr_channel>;
+	status = "disabled";
+};
+
 &dcmipp {
 	status = "okay";
 	port {

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 09/16] perf: stm32: introduce DDRPERFM driver
  2025-07-11 14:49 ` [PATCH v2 09/16] perf: stm32: introduce DDRPERFM driver Clément Le Goffic
@ 2025-07-11 16:04   ` Jonathan Cameron
  2025-07-15  9:49     ` Clement LE GOFFIC
  2025-07-14 19:39   ` Dan Carpenter
  1 sibling, 1 reply; 32+ messages in thread
From: Jonathan Cameron @ 2025-07-11 16:04 UTC (permalink / raw)
  To: Clément Le Goffic
  Cc: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic,
	linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk

On Fri, 11 Jul 2025 16:49:01 +0200
Clément Le Goffic <clement.legoffic@foss.st.com> wrote:

> Introduce the driver for the DDR Performance Monitor available on
> STM32MPU SoC.
> 
> On STM32MP2 platforms, the DDRPERFM allows to monitor up to 8 DDR events
> that come from the DDR Controller such as read or write events.
> 
> On STM32MP1 platforms, the DDRPERFM cannot monitor any event on any
> counter, there is a notion of set of events.
> Events from different sets cannot be monitored at the same time.
> The first chosen event selects the set.
> The set is coded in the first two bytes of the config value which is on 4
> bytes.
> 
> On STM32MP25x series, the DDRPERFM clock is shared with the DDR controller
> and may be secured by bootloaders.
> Access controllers allow to check access to a resource. Use the access
> controller defined in the devicetree to know about the access to the
> DDRPERFM clock.
> 
> Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>

Hi Clément,

A quick drive by review as it's Friday afternoon and I was curious..

Mostly superficial stuff. I didn't look closely at the perf logic.

Jonathan

> diff --git a/drivers/perf/stm32_ddr_pmu.c b/drivers/perf/stm32_ddr_pmu.c
> new file mode 100644
> index 000000000000..1be5bbe12978
> --- /dev/null
> +++ b/drivers/perf/stm32_ddr_pmu.c
> @@ -0,0 +1,910 @@

> +#define EVENT_NUMBER(group, index)	(((group) << 8) | (index))
> +#define GROUP_VALUE(event_number)		((event_number) >> 8)
> +#define EVENT_INDEX(event_number)	((event_number) & 0xFF)

Prefix these macro names with something driver specific.  They are
very likely to clash with something in a header in future otherwise.

> +
> +enum stm32_ddr_pmu_memory_type {
> +	STM32_DDR_PMU_LPDDR4,
> +	STM32_DDR_PMU_LPDDR3,
> +	STM32_DDR_PMU_DDR4,
> +	STM32_DDR_PMU_DDR3

This should have a trailing comma as might well be more
added in future if this IP gets used in more devices.

> +};
>


> +
> +static const struct attribute_group *stm32_ddr_pmu_attr_groups_mp2[] = {
> +	&stm32_ddr_pmu_events_attrs_group_mp2,
> +	&stm32_ddr_pmu_format_attr_group,
> +	NULL,

No comma needed on terminating entries.

> +};
> +
> +static int stm32_ddr_pmu_device_probe(struct platform_device *pdev)
> +{
> +	struct stm32_firewall firewall;
> +	struct stm32_ddr_pmu *pmu;
> +	struct reset_control *rst;
> +	struct resource *res;
> +	int ret;
> +
> +	pmu = devm_kzalloc(&pdev->dev, struct_size(pmu, counters, MP2_CNT_NB), GFP_KERNEL);
> +	if (!pmu)
> +		return -ENOMEM;
> +
> +	platform_set_drvdata(pdev, pmu);
> +	pmu->dev = &pdev->dev;
> +
> +	pmu->cfg = device_get_match_data(&pdev->dev);
> +
> +	pmu->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
> +	if (IS_ERR(pmu->membase))
> +		return PTR_ERR(pmu->membase);
> +
> +	if (of_property_present(pmu->dev->of_node, "access-controllers")) {
> +		ret = stm32_firewall_get_firewall(pmu->dev->of_node, &firewall, 1);
> +		if (ret)
> +			return dev_err_probe(pmu->dev, ret, "Failed to get firewall\n");
> +		ret = stm32_firewall_grant_access_by_id(&firewall, firewall.firewall_id);
> +		if (ret)
> +			return dev_err_probe(pmu->dev, ret, "Failed to grant access\n");
> +	}
> +
> +	pmu->clk = devm_clk_get_optional_prepared(pmu->dev, NULL);

Given there are quite a few uses of pmu->dev, maybe worth a local
struct device *dev = &pdev->dev; at the top and use dev to replace all these.

> +	if (IS_ERR(pmu->clk))
> +		return dev_err_probe(pmu->dev, PTR_ERR(pmu->clk), "Failed to get prepare clock\n");
> +
> +	clk_enable(pmu->clk);
> +
> +	rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);

You mix and match between pdev->dev, and pmu->dev. Good to pick one or use local
variable as suggested above.

> +	if (IS_ERR(rst)) {
> +		clk_disable_unprepare(pmu->clk);
Given use of _prepared() get above. This doesn't look right - the unprepare
should be handled by devm unwinding. clk_disable() 
> +		return dev_err_probe(&pdev->dev, PTR_ERR(rst), "Failed to get reset\n");
> +	}
> +
> +	reset_control_assert(rst);
> +	reset_control_deassert(rst);
> +
> +	pmu->poll_period = ms_to_ktime(POLL_MS);
> +	hrtimer_setup(&pmu->hrtimer, stm32_ddr_pmu_poll, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> +
> +	for (int i = 0; i < MP2_CNT_NB; i++)
> +		INIT_LIST_HEAD(&pmu->counters[i]);
> +
> +	pmu->selected_set = -1;
> +
> +	pmu->pmu = (struct pmu) {
> +		.task_ctx_nr = perf_invalid_context,
> +		.start = stm32_ddr_pmu_event_start,
> +		.stop = stm32_ddr_pmu_event_stop,
> +		.add = stm32_ddr_pmu_event_add,
> +		.del = stm32_ddr_pmu_event_del,
> +		.read = stm32_ddr_pmu_event_read,
> +		.event_init = stm32_ddr_pmu_event_init,
> +		.attr_groups = pmu->cfg->attribute,
> +		.module = THIS_MODULE,
> +	};
> +
> +	ret = perf_pmu_register(&pmu->pmu, DRIVER_NAME, -1);

Calling this exposes user interfaces etc.  Does it really make sense to
do that and then write another register?  I'd normally expect this
last in probe.

> +	if (ret) {
> +		clk_disable_unprepare(pmu->clk);

As above.

> +		return dev_err_probe(&pdev->dev, ret,
> +				     "Couldn't register DDRPERFM driver as a PMU\n");
> +	}
> +
> +	if (pmu->cfg->regs->dram_inf.reg) {
> +		ret = stm32_ddr_pmu_get_memory_type(pmu);
> +		if (ret) {
> +			perf_pmu_unregister(&pmu->pmu);
> +			clk_disable_unprepare(pmu->clk);
> +			return dev_err_probe(&pdev->dev, ret, "Failed to get memory type\n");
> +		}
> +
> +		writel_relaxed(pmu->dram_type, pmu->membase + pmu->cfg->regs->dram_inf.reg);
> +	}
> +
> +	clk_disable(pmu->clk);
> +
> +	return 0;
> +}

> +static const struct stm32_ddr_pmu_regspec stm32_ddr_pmu_regspec_mp2 = {
> +	.stop =		{ DDRPERFM_CTRL, CTRL_STOP },
> +	.start =	{ DDRPERFM_CTRL, CTRL_START },
> +	.status =	{ DDRPERFM_MP2_STATUS, MP2_STATUS_BUSY },
> +	.clear_cnt =	{ DDRPERFM_CLR, MP2_CLR_CNT},
> +	.clear_time =	{ DDRPERFM_CLR, MP2_CLR_TIME},

Spaces before } are missing
There are a few others above that I'll not mention directly.


> +	.cfg0 =		{ DDRPERFM_MP2_CFG0 },
> +	.cfg1 =		{ DDRPERFM_MP2_CFG1 },
> +	.enable =	{ DDRPERFM_MP2_CFG5 },
> +	.dram_inf =	{ DDRPERFM_MP2_DRAMINF },
> +	.counter_time =	{ DDRPERFM_MP2_TCNT },
> +	.counter_evt =	{
> +				{ DDRPERFM_MP2_EVCNT(0) },
Somewhat unusual formatting though neat I guess so fine if you
really like it!.
	.counter_evt =	{
		{ DDRPERFM_MP2_EVCNT(0) },

would be what I'd normally expect.
> +				{ DDRPERFM_MP2_EVCNT(1) },
> +				{ DDRPERFM_MP2_EVCNT(2) },
> +				{ DDRPERFM_MP2_EVCNT(3) },
> +				{ DDRPERFM_MP2_EVCNT(4) },
> +				{ DDRPERFM_MP2_EVCNT(5) },
> +				{ DDRPERFM_MP2_EVCNT(6) },
> +				{ DDRPERFM_MP2_EVCNT(7) },
> +	},
> +};
> +
> +static const struct stm32_ddr_pmu_cfg stm32_ddr_pmu_cfg_mp1 = {
> +	.regs = &stm32_ddr_pmu_regspec_mp1,
> +	.attribute = stm32_ddr_pmu_attr_groups_mp1,
> +	.counters_nb = MP1_CNT_NB,
> +	.evt_counters_nb = MP1_CNT_NB - 1, /* Time counter is not an event counter */
> +	.time_cnt_idx = MP1_TIME_CNT_IDX,
> +	.get_counter = stm32_ddr_pmu_get_event_counter_mp1,
> +};
> +
> +static const struct stm32_ddr_pmu_cfg stm32_ddr_pmu_cfg_mp2 = {
> +	.regs = &stm32_ddr_pmu_regspec_mp2,
> +	.attribute = stm32_ddr_pmu_attr_groups_mp2,
> +	.counters_nb = MP2_CNT_NB,
> +	.evt_counters_nb = MP2_CNT_NB - 1, /* Time counter is an event counter */
> +	.time_cnt_idx = MP2_TIME_CNT_IDX,
> +	.get_counter = stm32_ddr_pmu_get_event_counter_mp2,
> +};
> +
> +static const struct dev_pm_ops stm32_ddr_pmu_pm_ops = {
> +	SET_SYSTEM_SLEEP_PM_OPS(NULL, stm32_ddr_pmu_device_resume)
> +};

static DEFINE_SIMPLE_DEV_PM_OPS() looks appropriate here.


> +
> +static const struct of_device_id stm32_ddr_pmu_of_match[] = {
> +	{
> +		.compatible = "st,stm32mp131-ddr-pmu",
> +		.data = &stm32_ddr_pmu_cfg_mp1
> +	},
> +	{
> +		.compatible = "st,stm32mp251-ddr-pmu",
> +		.data = &stm32_ddr_pmu_cfg_mp2
> +	},
> +	{ },

No comma need after terminating entry.  Nice to make it hard
to accidentally add entries after one of these!

> +};
> +MODULE_DEVICE_TABLE(of, stm32_ddr_pmu_of_match);
> +
> +static struct platform_driver stm32_ddr_pmu_driver = {
> +	.driver = {
> +		.name = DRIVER_NAME,
> +		.pm = pm_sleep_ptr(&stm32_ddr_pmu_pm_ops),
> +		.of_match_table = stm32_ddr_pmu_of_match,
> +	},
> +	.probe = stm32_ddr_pmu_device_probe,
> +	.remove = stm32_ddr_pmu_device_remove,
> +};
> +
> +module_platform_driver(stm32_ddr_pmu_driver);
> +
> +MODULE_AUTHOR("Clément Le Goffic");
> +MODULE_DESCRIPTION("STMicroelectronics STM32 DDR performance monitor driver");
> +MODULE_LICENSE("GPL");
> 


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms
  2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
                   ` (15 preceding siblings ...)
  2025-07-11 14:49 ` [PATCH v2 16/16] arm64: dts: st: support ddrperfm on stm32mp257f-ev1 Clément Le Goffic
@ 2025-07-14 15:24 ` Rob Herring (Arm)
  16 siblings, 0 replies; 32+ messages in thread
From: Rob Herring (Arm) @ 2025-07-14 15:24 UTC (permalink / raw)
  To: Clément Le Goffic
  Cc: Michael Turquette, linux-kernel, Gabriel Fernandez, linux-clk,
	Jonathan Corbet, Krzysztof Kozlowski, Conor Dooley, Philipp Zabel,
	Krzysztof Kozlowski, Gatien Chevallier, Le Goffic, linux-stm32,
	Will Deacon, Maxime Coquelin, linux-arm-kernel, Mark Rutland,
	linux-perf-users, devicetree, Stephen Boyd, Alexandre Torgue,
	linux-doc


On Fri, 11 Jul 2025 16:48:52 +0200, Clément Le Goffic wrote:
> This patch series introduces the DDR Performance Monitor (DDRPERFM) support for
> STM32MP platforms.
> 
> The series firstly improves the STM32MP25 RCC driver to make it usable
> as an access controller, needed for driver probe.
> 
> It also includes the addition of device tree bindings, the HDP driver,
> documentation and updates to the device tree files for
> STM32MP13, STM32MP15 and STM32MP25 SoCs.
> The series also updates the MAINTAINERS file to include myself as the
> maintainer for the STM32 DDR PMU driver.
> 
> Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
> ---
> Changes in v2:
> - MAINTAINERS:
>     Due to reorganisation, my contract with ST ends at the end of this month
>     and I will no longer have access to this mailbox.
>     Therefore, I will be available for any mission related to embedded and
>     kernel linux.
>     Change email address in MAINTAINERS file for STM32 DDR PMU driver.
> - devicetrees:
>   -stm32mp257f-dk: add LPDDR4 channel
>   -stm32mp257f-ev1: add DDR4 channel
> - dt-bindings:
>   - perf:
>     - Change Maintainer email address
>     - Drop obvious descriptions (clocks and reset property)
>     - Drop redundant "bindings" in commit message
>     - Drop unneedded "stm32mp151-ddr-pmu" compatible
>     - s/st,dram-type/memory-channel/, memory-channel property is not in
>       dtschema library so it will produce an error in the v2.
>   - rcc:
>     - Add required "access-controller-cells" property in example
>   - ddr-channel:
>     - Add bindings as per jedec,lpddrX-channel bindings
> - driver:
>   - Substitute the parsing of the 'st,dram-type' vendor devicetree
>     property value with the parsing of the [lp]ddr channel compatible
>   - Remove unneeded "stm32mp151-ddr-pmu" compatible
>   - Use dev_err_probe when possible
>   - Assert and deassert reset line unconditionnaly
>   - Use `devm_reset_control_get_optional_exclusive` instead of
>     `of_property_present` then `devm_reset_control_get`
>   - Use `devm_clk_get_optional_prepared` instead of `of_property_present`
>     then `devm_clk_get_prepared`
>   - Disable and unprepare the clock at end of probe
>   - Add io.h include as per LKP test report
>   - Removed `of_match_ptr` reference in `platform_driver` struct
>   - Add `pm_sleep_ptr` macro for `platform_driver` struct's `pm` field
>   - Link to v1: https://lore.kernel.org/r/20250623-ddrperfm-upstream-v1-0-7dffff168090@foss.st.com
> 
> ---
> Clément Le Goffic (16):
>       bus: firewall: move stm32_firewall header file in include folder
>       dt-bindings: stm32: stm32mp25: add `access-controller-cell` property
>       clk: stm32mp25: add firewall grant_access ops
>       arm64: dts: st: set rcc as an access-controller
>       dt-bindings: memory: add jedec,ddr[3-4]-channel binding
>       arm64: dts: st: add LPDDR channel to stm32mp257f-dk board
>       arm64: dts: st: add DDR channel to stm32mp257f-ev1 board
>       dt-bindings: perf: stm32: introduce DDRPERFM dt-bindings
>       perf: stm32: introduce DDRPERFM driver
>       Documentation: perf: stm32: add ddrperfm support
>       MAINTAINERS: add myself as STM32 DDR PMU maintainer
>       ARM: dts: stm32: add ddrperfm on stm32mp131
>       ARM: dts: stm32: add ddrperfm on stm32mp151
>       arm64: dts: st: add ddrperfm on stm32mp251
>       arm64: dts: st: support ddrperfm on stm32mp257f-dk
>       arm64: dts: st: support ddrperfm on stm32mp257f-ev1
> 
>  Documentation/admin-guide/perf/index.rst           |   1 +
>  Documentation/admin-guide/perf/stm32-ddr-pmu.rst   |  86 ++
>  .../bindings/clock/st,stm32mp25-rcc.yaml           |   7 +
>  .../memory-controllers/ddr/jedec,ddr-channel.yaml  |  53 ++
>  .../devicetree/bindings/perf/st,stm32-ddr-pmu.yaml |  87 ++
>  MAINTAINERS                                        |   7 +
>  arch/arm/boot/dts/st/stm32mp131.dtsi               |   7 +
>  arch/arm/boot/dts/st/stm32mp151.dtsi               |   7 +
>  arch/arm64/boot/dts/st/stm32mp251.dtsi             |   8 +
>  arch/arm64/boot/dts/st/stm32mp257f-dk.dts          |  12 +
>  arch/arm64/boot/dts/st/stm32mp257f-ev1.dts         |  10 +
>  drivers/bus/stm32_etzpc.c                          |   3 +-
>  drivers/bus/stm32_firewall.c                       |   3 +-
>  drivers/bus/stm32_rifsc.c                          |   3 +-
>  drivers/clk/stm32/clk-stm32mp25.c                  |  40 +-
>  drivers/perf/Kconfig                               |  11 +
>  drivers/perf/Makefile                              |   1 +
>  drivers/perf/stm32_ddr_pmu.c                       | 910 +++++++++++++++++++++
>  {drivers => include/linux}/bus/stm32_firewall.h    |   0
>  19 files changed, 1249 insertions(+), 7 deletions(-)
> ---
> base-commit: d7b8f8e20813f0179d8ef519541a3527e7661d3a
> change-id: 20250526-ddrperfm-upstream-bf07f57775da
> 
> Best regards,
> --
> Clément Le Goffic <clement.legoffic@foss.st.com>
> 
> 
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

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

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Base: using specified base-commit d7b8f8e20813f0179d8ef519541a3527e7661d3a

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm/boot/dts/st/' for 20250711-ddrperfm-upstream-v2-0-cdece720348f@foss.st.com:

arch/arm/boot/dts/st/stm32mp157a-icore-stm32mp1-edimm2.2.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157c-odyssey.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp153c-lxa-tac-gen3.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157c-dk2.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157c-ev1.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp151a-dhcor-testbench.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157c-phycore-stm32mp1-3.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157c-dhcom-picoitx.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp153c-lxa-fairytux2-gen2.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157c-dhcom-pdk2.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157c-ed1.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp153c-lxa-fairytux2-gen1.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157a-microgea-stm32mp1-microdev2.0.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp153c-dhcor-drc-compact.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157a-microgea-stm32mp1-microdev2.0-of7.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp151a-prtt1a.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157a-dk1-scmi.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp151c-mect1s.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157a-stinger96.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157a-dhcor-avenger96.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp153c-mecio1r1.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp151a-prtt1s.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp151a-prtt1c.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157a-icore-stm32mp1-ctouch2-of10.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157c-ultra-fly-sbc.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157a-dk1.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157c-osd32mp1-red.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp153c-dhcom-drc02.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157c-emsbc-argon.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp151c-plyaqm.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157a-iot-box.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157c-lxa-mc1.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157c-ev1-scmi.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157a-avenger96.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157c-ed1-scmi.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157c-lxa-tac-gen2.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157c-lxa-tac-gen1.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp151c-mecio1r0.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157a-icore-stm32mp1-ctouch2.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#
arch/arm/boot/dts/st/stm32mp157c-dk2-scmi.dtb: perf@5a007000 (st,stm32mp151-ddr-pmu): compatible: ['st,stm32mp151-ddr-pmu', 'st,stm32mp131-ddr-pmu'] is too long
	from schema $id: http://devicetree.org/schemas/perf/st,stm32-ddr-pmu.yaml#






^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 09/16] perf: stm32: introduce DDRPERFM driver
  2025-07-11 14:49 ` [PATCH v2 09/16] perf: stm32: introduce DDRPERFM driver Clément Le Goffic
  2025-07-11 16:04   ` Jonathan Cameron
@ 2025-07-14 19:39   ` Dan Carpenter
  1 sibling, 0 replies; 32+ messages in thread
From: Dan Carpenter @ 2025-07-14 19:39 UTC (permalink / raw)
  To: oe-kbuild, Clément Le Goffic, Will Deacon, Mark Rutland,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Maxime Coquelin,
	Alexandre Torgue, Philipp Zabel, Jonathan Corbet,
	Gatien Chevallier, Michael Turquette, Stephen Boyd,
	Gabriel Fernandez, Le Goffic
  Cc: lkp, oe-kbuild-all, linux-arm-kernel, linux-perf-users,
	devicetree, linux-stm32, linux-kernel, linux-doc, linux-clk,
	Clément Le Goffic

Hi Clément,

kernel test robot noticed the following build warnings:

url:    https://github.com/intel-lab-lkp/linux/commits/Cl-ment-Le-Goffic/bus-firewall-move-stm32_firewall-header-file-in-include-folder/20250712-030518
base:   d7b8f8e20813f0179d8ef519541a3527e7661d3a
patch link:    https://lore.kernel.org/r/20250711-ddrperfm-upstream-v2-9-cdece720348f%40foss.st.com
patch subject: [PATCH v2 09/16] perf: stm32: introduce DDRPERFM driver
config: sh-randconfig-r071-20250712 (https://download.01.org/0day-ci/archive/20250712/202507122125.eve8lg60-lkp@intel.com/config)
compiler: sh4-linux-gcc (GCC) 13.4.0

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202507122125.eve8lg60-lkp@intel.com/

smatch warnings:
drivers/perf/stm32_ddr_pmu.c:380 stm32_ddr_pmu_get_counter() warn: variable dereferenced before check 'pmu' (see line 376)
drivers/perf/stm32_ddr_pmu.c:380 stm32_ddr_pmu_get_counter() warn: variable dereferenced before check 'event' (see line 377)

vim +/pmu +380 drivers/perf/stm32_ddr_pmu.c

73af3c4ba702d7 Clément Le Goffic 2025-07-11  374  static int stm32_ddr_pmu_get_counter(struct stm32_ddr_pmu *pmu, struct perf_event *event)
73af3c4ba702d7 Clément Le Goffic 2025-07-11  375  {
73af3c4ba702d7 Clément Le Goffic 2025-07-11 @376  	u32 time_cnt_idx = pmu->cfg->time_cnt_idx;
                                                                           ^^^^^^^^

73af3c4ba702d7 Clément Le Goffic 2025-07-11 @377  	u32 config = event->attr.config;
                                                                     ^^^^^^^

73af3c4ba702d7 Clément Le Goffic 2025-07-11  378  	struct stm32_ddr_cnt *cnt;
73af3c4ba702d7 Clément Le Goffic 2025-07-11  379  
73af3c4ba702d7 Clément Le Goffic 2025-07-11 @380  	if (!pmu || !event)
                                                            ^^^^^^^^^^^^^^
Checks are too late.  The variables have already been dereferenced.

73af3c4ba702d7 Clément Le Goffic 2025-07-11  381  		return -EINVAL;
73af3c4ba702d7 Clément Le Goffic 2025-07-11  382  
73af3c4ba702d7 Clément Le Goffic 2025-07-11  383  	pmu->selected_set = GROUP_VALUE(config);
73af3c4ba702d7 Clément Le Goffic 2025-07-11  384  
73af3c4ba702d7 Clément Le Goffic 2025-07-11  385  	if (config == TIME_CNT) {

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 02/16] dt-bindings: stm32: stm32mp25: add `access-controller-cell` property
  2025-07-11 14:48 ` [PATCH v2 02/16] dt-bindings: stm32: stm32mp25: add `access-controller-cell` property Clément Le Goffic
@ 2025-07-15  3:17   ` Rob Herring
  2025-07-15  7:37     ` Gatien CHEVALLIER
  2025-07-15 11:47     ` Clement LE GOFFIC
  0 siblings, 2 replies; 32+ messages in thread
From: Rob Herring @ 2025-07-15  3:17 UTC (permalink / raw)
  To: Clément Le Goffic
  Cc: Will Deacon, Mark Rutland, Krzysztof Kozlowski, Conor Dooley,
	Maxime Coquelin, Alexandre Torgue, Philipp Zabel, Jonathan Corbet,
	Gatien Chevallier, Michael Turquette, Stephen Boyd,
	Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic,
	linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk

On Fri, Jul 11, 2025 at 04:48:54PM +0200, Clément Le Goffic wrote:
> RCC is able to check the availability of a clock.
> Allow to query the RCC with a firewall ID.

If it is tied to a clock, do we need another provider? We have the 
"protected clocks" thing, but that might be a bit different.

> 
> Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
> ---
>  Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml b/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml
> index 88e52f10d1ec..4d471e3d89bc 100644
> --- a/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml
> +++ b/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml
> @@ -31,6 +31,11 @@ properties:
>    '#reset-cells':
>      const: 1
>  
> +  '#access-controller-cells':
> +    const: 1
> +    description:
> +      Contains the firewall ID associated to the peripheral.
> +
>    clocks:
>      items:
>        - description: CK_SCMI_HSE High Speed External oscillator (8 to 48 MHz)
> @@ -123,6 +128,7 @@ required:
>    - reg
>    - '#clock-cells'
>    - '#reset-cells'
> +  - '#access-controller-cells'
>    - clocks
>  
>  additionalProperties: false
> @@ -136,6 +142,7 @@ examples:
>          reg = <0x44200000 0x10000>;
>          #clock-cells = <1>;
>          #reset-cells = <1>;
> +        #access-controller-cells = <1>;
>          clocks =  <&scmi_clk CK_SCMI_HSE>,
>                    <&scmi_clk CK_SCMI_HSI>,
>                    <&scmi_clk CK_SCMI_MSI>,
> 
> -- 
> 2.43.0
> 

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 06/16] arm64: dts: st: add LPDDR channel to stm32mp257f-dk board
  2025-07-11 14:48 ` [PATCH v2 06/16] arm64: dts: st: add LPDDR channel to stm32mp257f-dk board Clément Le Goffic
@ 2025-07-15  3:20   ` Rob Herring
  2025-07-15  8:32     ` Clement LE GOFFIC
  0 siblings, 1 reply; 32+ messages in thread
From: Rob Herring @ 2025-07-15  3:20 UTC (permalink / raw)
  To: Clément Le Goffic
  Cc: Will Deacon, Mark Rutland, Krzysztof Kozlowski, Conor Dooley,
	Maxime Coquelin, Alexandre Torgue, Philipp Zabel, Jonathan Corbet,
	Gatien Chevallier, Michael Turquette, Stephen Boyd,
	Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic,
	linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk

On Fri, Jul 11, 2025 at 04:48:58PM +0200, Clément Le Goffic wrote:
> Add 32bits LPDDR4 channel to the stm32mp257f-dk board.
> 
> Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
> ---
>  arch/arm64/boot/dts/st/stm32mp257f-dk.dts | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/st/stm32mp257f-dk.dts b/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
> index a278a1e3ce03..a97b41f14ecc 100644
> --- a/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
> +++ b/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
> @@ -54,6 +54,13 @@ led-blue {
>  		};
>  	};
>  
> +	lpddr_channel: lpddr4-channel {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		compatible = "jedec,lpddr4-channel";

Not tested because this doesn't match the binding.

> +		io-width = <32>;
> +	};

What would multiple channels look like? I think this needs some work. 
Like it should perhaps be within the memory node. It's a lot to just say 
32-bit LPDDR4 x1.

> +
>  	memory@80000000 {
>  		device_type = "memory";
>  		reg = <0x0 0x80000000 0x1 0x0>;
> 
> -- 
> 2.43.0
> 

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 02/16] dt-bindings: stm32: stm32mp25: add `access-controller-cell` property
  2025-07-15  3:17   ` Rob Herring
@ 2025-07-15  7:37     ` Gatien CHEVALLIER
  2025-07-15  8:19       ` Krzysztof Kozlowski
  2025-07-15 11:47     ` Clement LE GOFFIC
  1 sibling, 1 reply; 32+ messages in thread
From: Gatien CHEVALLIER @ 2025-07-15  7:37 UTC (permalink / raw)
  To: Rob Herring, Clément Le Goffic
  Cc: Will Deacon, Mark Rutland, Krzysztof Kozlowski, Conor Dooley,
	Maxime Coquelin, Alexandre Torgue, Philipp Zabel, Jonathan Corbet,
	Michael Turquette, Stephen Boyd, Gabriel Fernandez,
	Krzysztof Kozlowski, Le Goffic, linux-arm-kernel,
	linux-perf-users, devicetree, linux-stm32, linux-kernel,
	linux-doc, linux-clk

Hello Rob,

On 7/15/25 05:17, Rob Herring wrote:
> On Fri, Jul 11, 2025 at 04:48:54PM +0200, Clément Le Goffic wrote:
>> RCC is able to check the availability of a clock.
>> Allow to query the RCC with a firewall ID.
> 
> If it is tied to a clock, do we need another provider? We have the
> "protected clocks" thing, but that might be a bit different.
> 

I couldn't find any reference to "protected-clocks" outside of qcom
related code, is there a documentation? (Couldn't find it in
clocks.yaml).

The RCC is firewall-aware and has it's own firewall configuration at
RCC level for some system resources. When checking access to a clock,
or a reset, we're reading RCC registers, hence declaring it as an
access-controller.

A RCC resource's firewall configuration usually covers more than a
clock.

>>
>> Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
>> ---
>>   Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml | 7 +++++++
>>   1 file changed, 7 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml b/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml
>> index 88e52f10d1ec..4d471e3d89bc 100644
>> --- a/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml
>> +++ b/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml
>> @@ -31,6 +31,11 @@ properties:
>>     '#reset-cells':
>>       const: 1
>>   
>> +  '#access-controller-cells':
>> +    const: 1
>> +    description:
>> +      Contains the firewall ID associated to the peripheral.
>> +
>>     clocks:
>>       items:
>>         - description: CK_SCMI_HSE High Speed External oscillator (8 to 48 MHz)
>> @@ -123,6 +128,7 @@ required:
>>     - reg
>>     - '#clock-cells'
>>     - '#reset-cells'
>> +  - '#access-controller-cells'
>>     - clocks
>>   
>>   additionalProperties: false
>> @@ -136,6 +142,7 @@ examples:
>>           reg = <0x44200000 0x10000>;
>>           #clock-cells = <1>;
>>           #reset-cells = <1>;
>> +        #access-controller-cells = <1>;
>>           clocks =  <&scmi_clk CK_SCMI_HSE>,
>>                     <&scmi_clk CK_SCMI_HSI>,
>>                     <&scmi_clk CK_SCMI_MSI>,
>>
>> -- 
>> 2.43.0
>>

Best regards,
Gatien

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 02/16] dt-bindings: stm32: stm32mp25: add `access-controller-cell` property
  2025-07-15  7:37     ` Gatien CHEVALLIER
@ 2025-07-15  8:19       ` Krzysztof Kozlowski
  2025-07-15  8:40         ` Gatien CHEVALLIER
  0 siblings, 1 reply; 32+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-15  8:19 UTC (permalink / raw)
  To: Gatien CHEVALLIER
  Cc: Rob Herring, Clément Le Goffic, Will Deacon, Mark Rutland,
	Krzysztof Kozlowski, Conor Dooley, Maxime Coquelin,
	Alexandre Torgue, Philipp Zabel, Jonathan Corbet,
	Michael Turquette, Stephen Boyd, Gabriel Fernandez, Le Goffic,
	linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk

On Tue, Jul 15, 2025 at 09:37:00AM +0200, Gatien CHEVALLIER wrote:
> Hello Rob,
> 
> On 7/15/25 05:17, Rob Herring wrote:
> > On Fri, Jul 11, 2025 at 04:48:54PM +0200, Clément Le Goffic wrote:
> > > RCC is able to check the availability of a clock.
> > > Allow to query the RCC with a firewall ID.
> > 
> > If it is tied to a clock, do we need another provider? We have the
> > "protected clocks" thing, but that might be a bit different.
> > 
> 
> I couldn't find any reference to "protected-clocks" outside of qcom
> related code, is there a documentation? (Couldn't find it in
> clocks.yaml).

Huh? protected-clocks is in clocks.yaml... It is there with an explanation.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 06/16] arm64: dts: st: add LPDDR channel to stm32mp257f-dk board
  2025-07-15  3:20   ` Rob Herring
@ 2025-07-15  8:32     ` Clement LE GOFFIC
  2025-07-15 15:02       ` Rob Herring
  0 siblings, 1 reply; 32+ messages in thread
From: Clement LE GOFFIC @ 2025-07-15  8:32 UTC (permalink / raw)
  To: Rob Herring
  Cc: Will Deacon, Mark Rutland, Krzysztof Kozlowski, Conor Dooley,
	Maxime Coquelin, Alexandre Torgue, Philipp Zabel, Jonathan Corbet,
	Gatien Chevallier, Michael Turquette, Stephen Boyd,
	Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic,
	linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk

Hi Rob,

Thanks for the review !

On 7/15/25 05:20, Rob Herring wrote:
> On Fri, Jul 11, 2025 at 04:48:58PM +0200, Clément Le Goffic wrote:
>> Add 32bits LPDDR4 channel to the stm32mp257f-dk board.
>>
>> Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
>> ---
>>   arch/arm64/boot/dts/st/stm32mp257f-dk.dts | 7 +++++++
>>   1 file changed, 7 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/st/stm32mp257f-dk.dts b/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
>> index a278a1e3ce03..a97b41f14ecc 100644
>> --- a/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
>> +++ b/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
>> @@ -54,6 +54,13 @@ led-blue {
>>   		};
>>   	};
>>   
>> +	lpddr_channel: lpddr4-channel {
>> +		#address-cells = <1>;
>> +		#size-cells = <0>;
>> +		compatible = "jedec,lpddr4-channel";
> 
> Not tested because this doesn't match the binding.

Hmm, I've tested with make dtbs_check and dt_binding_check and it didn't 
complain on my side.
What I have miss ?


> 
>> +		io-width = <32>;
>> +	};
> 
> What would multiple channels look like? I think this needs some work.
> Like it should perhaps be within the memory node. It's a lot to just say
> 32-bit LPDDR4 x1.

I guess something like two channels node following each other in the DT.
It can be in the memory node I don't know what are the stakes here.
I was inspired by the lpddr node here:
arch/arm/boot/dts/samsung/exynos5422-odroid-core.dtsi:336

Best regard,
Clément

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 02/16] dt-bindings: stm32: stm32mp25: add `access-controller-cell` property
  2025-07-15  8:19       ` Krzysztof Kozlowski
@ 2025-07-15  8:40         ` Gatien CHEVALLIER
  0 siblings, 0 replies; 32+ messages in thread
From: Gatien CHEVALLIER @ 2025-07-15  8:40 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Rob Herring, Clément Le Goffic, Will Deacon, Mark Rutland,
	Krzysztof Kozlowski, Conor Dooley, Maxime Coquelin,
	Alexandre Torgue, Philipp Zabel, Jonathan Corbet,
	Michael Turquette, Stephen Boyd, Gabriel Fernandez, Le Goffic,
	linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk



On 7/15/25 10:19, Krzysztof Kozlowski wrote:
> On Tue, Jul 15, 2025 at 09:37:00AM +0200, Gatien CHEVALLIER wrote:
>> Hello Rob,
>>
>> On 7/15/25 05:17, Rob Herring wrote:
>>> On Fri, Jul 11, 2025 at 04:48:54PM +0200, Clément Le Goffic wrote:
>>>> RCC is able to check the availability of a clock.
>>>> Allow to query the RCC with a firewall ID.
>>>
>>> If it is tied to a clock, do we need another provider? We have the
>>> "protected clocks" thing, but that might be a bit different.
>>>
>>
>> I couldn't find any reference to "protected-clocks" outside of qcom
>> related code, is there a documentation? (Couldn't find it in
>> clocks.yaml).
> 
> Huh? protected-clocks is in clocks.yaml... It is there with an explanation.
> 
> Best regards,
> Krzysztof
> 

Ah, I was looking at Rob's repo, my bad.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 09/16] perf: stm32: introduce DDRPERFM driver
  2025-07-11 16:04   ` Jonathan Cameron
@ 2025-07-15  9:49     ` Clement LE GOFFIC
  0 siblings, 0 replies; 32+ messages in thread
From: Clement LE GOFFIC @ 2025-07-15  9:49 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Will Deacon, Mark Rutland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Maxime Coquelin, Alexandre Torgue, Philipp Zabel,
	Jonathan Corbet, Gatien Chevallier, Michael Turquette,
	Stephen Boyd, Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic,
	linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk

Hi Jonathan,

On 7/11/25 18:04, Jonathan Cameron wrote:
> On Fri, 11 Jul 2025 16:49:01 +0200
> Clément Le Goffic <clement.legoffic@foss.st.com> wrote:
> 
>> Introduce the driver for the DDR Performance Monitor available on
>> STM32MPU SoC.
>>
>> On STM32MP2 platforms, the DDRPERFM allows to monitor up to 8 DDR events
>> that come from the DDR Controller such as read or write events.
>>
>> On STM32MP1 platforms, the DDRPERFM cannot monitor any event on any
>> counter, there is a notion of set of events.
>> Events from different sets cannot be monitored at the same time.
>> The first chosen event selects the set.
>> The set is coded in the first two bytes of the config value which is on 4
>> bytes.
>>
>> On STM32MP25x series, the DDRPERFM clock is shared with the DDR controller
>> and may be secured by bootloaders.
>> Access controllers allow to check access to a resource. Use the access
>> controller defined in the devicetree to know about the access to the
>> DDRPERFM clock.
>>
>> Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
> 
> Hi Clément,
> 
> A quick drive by review as it's Friday afternoon and I was curious..
> 
> Mostly superficial stuff. I didn't look closely at the perf logic.

Thank you for the review.
The perf logic is new to me so if you have any suggestion, you're welcome.


> 
>> diff --git a/drivers/perf/stm32_ddr_pmu.c b/drivers/perf/stm32_ddr_pmu.c
>> new file mode 100644
>> index 000000000000..1be5bbe12978
>> --- /dev/null
>> +++ b/drivers/perf/stm32_ddr_pmu.c
>> @@ -0,0 +1,910 @@
> 
>> +#define EVENT_NUMBER(group, index)	(((group) << 8) | (index))
>> +#define GROUP_VALUE(event_number)		((event_number) >> 8)
>> +#define EVENT_INDEX(event_number)	((event_number) & 0xFF)
> 
> Prefix these macro names with something driver specific.  They are
> very likely to clash with something in a header in future otherwise.

Ok

> 
>> +
>> +enum stm32_ddr_pmu_memory_type {
>> +	STM32_DDR_PMU_LPDDR4,
>> +	STM32_DDR_PMU_LPDDR3,
>> +	STM32_DDR_PMU_DDR4,
>> +	STM32_DDR_PMU_DDR3
> 
> This should have a trailing comma as might well be more
> added in future if this IP gets used in more devices.

Ok

>> +};
>>
> 
> 
>> +
>> +static const struct attribute_group *stm32_ddr_pmu_attr_groups_mp2[] = {
>> +	&stm32_ddr_pmu_events_attrs_group_mp2,
>> +	&stm32_ddr_pmu_format_attr_group,
>> +	NULL,
> 
> No comma needed on terminating entries.

Ok, will also be fixed for `stm32_ddr_pmu_attr_groups_mp1[]` and
`stm32_ddr_pmu_format_attrs[]`
> 
>> +};
>> +
>> +static int stm32_ddr_pmu_device_probe(struct platform_device *pdev)
>> +{
>> +	struct stm32_firewall firewall;
>> +	struct stm32_ddr_pmu *pmu;
>> +	struct reset_control *rst;
>> +	struct resource *res;
>> +	int ret;
>> +
>> +	pmu = devm_kzalloc(&pdev->dev, struct_size(pmu, counters, MP2_CNT_NB), GFP_KERNEL);
>> +	if (!pmu)
>> +		return -ENOMEM;
>> +
>> +	platform_set_drvdata(pdev, pmu);
>> +	pmu->dev = &pdev->dev;
>> +
>> +	pmu->cfg = device_get_match_data(&pdev->dev);
>> +
>> +	pmu->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
>> +	if (IS_ERR(pmu->membase))
>> +		return PTR_ERR(pmu->membase);
>> +
>> +	if (of_property_present(pmu->dev->of_node, "access-controllers")) {
>> +		ret = stm32_firewall_get_firewall(pmu->dev->of_node, &firewall, 1);
>> +		if (ret)
>> +			return dev_err_probe(pmu->dev, ret, "Failed to get firewall\n");
>> +		ret = stm32_firewall_grant_access_by_id(&firewall, firewall.firewall_id);
>> +		if (ret)
>> +			return dev_err_probe(pmu->dev, ret, "Failed to grant access\n");
>> +	}
>> +
>> +	pmu->clk = devm_clk_get_optional_prepared(pmu->dev, NULL);
> 
> Given there are quite a few uses of pmu->dev, maybe worth a local
> struct device *dev = &pdev->dev; at the top and use dev to replace all these.

As I need pmu->dev elsewhere in the driver I'll stick to it and replace 
all &pdev->dev

> 
>> +	if (IS_ERR(pmu->clk))
>> +		return dev_err_probe(pmu->dev, PTR_ERR(pmu->clk), "Failed to get prepare clock\n");
>> +
>> +	clk_enable(pmu->clk);
>> +
>> +	rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
> 
> You mix and match between pdev->dev, and pmu->dev. Good to pick one or use local
> variable as suggested above.

Ok
> 
>> +	if (IS_ERR(rst)) {
>> +		clk_disable_unprepare(pmu->clk);
> Given use of _prepared() get above. This doesn't look right - the unprepare
> should be handled by devm unwinding. clk_disable()

Oh you're right, I can fix this unwinding issue by using 
`devm_clk_get_optional_enabled()` instead of 
`devm_clk_get_optional_prepared()` and remove the `clk_enable()` so all 
`clk_disable_unprepare()` disappear from the probe


>> +		return dev_err_probe(&pdev->dev, PTR_ERR(rst), "Failed to get reset\n");
>> +	}
>> +
>> +	reset_control_assert(rst);
>> +	reset_control_deassert(rst);
>> +
>> +	pmu->poll_period = ms_to_ktime(POLL_MS);
>> +	hrtimer_setup(&pmu->hrtimer, stm32_ddr_pmu_poll, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
>> +
>> +	for (int i = 0; i < MP2_CNT_NB; i++)
>> +		INIT_LIST_HEAD(&pmu->counters[i]);
>> +
>> +	pmu->selected_set = -1;
>> +
>> +	pmu->pmu = (struct pmu) {
>> +		.task_ctx_nr = perf_invalid_context,
>> +		.start = stm32_ddr_pmu_event_start,
>> +		.stop = stm32_ddr_pmu_event_stop,
>> +		.add = stm32_ddr_pmu_event_add,
>> +		.del = stm32_ddr_pmu_event_del,
>> +		.read = stm32_ddr_pmu_event_read,
>> +		.event_init = stm32_ddr_pmu_event_init,
>> +		.attr_groups = pmu->cfg->attribute,
>> +		.module = THIS_MODULE,
>> +	};
>> +
>> +	ret = perf_pmu_register(&pmu->pmu, DRIVER_NAME, -1);
> 
> Calling this exposes user interfaces etc.  Does it really make sense to
> do that and then write another register?  I'd normally expect this
> last in probe.

Indeed, will move it at the end of the probe

> 
>> +	if (ret) {
>> +		clk_disable_unprepare(pmu->clk);
> 
> As above.

Ok
> 
>> +		return dev_err_probe(&pdev->dev, ret,
>> +				     "Couldn't register DDRPERFM driver as a PMU\n");
>> +	}
>> +
>> +	if (pmu->cfg->regs->dram_inf.reg) {
>> +		ret = stm32_ddr_pmu_get_memory_type(pmu);
>> +		if (ret) {
>> +			perf_pmu_unregister(&pmu->pmu);
>> +			clk_disable_unprepare(pmu->clk);
>> +			return dev_err_probe(&pdev->dev, ret, "Failed to get memory type\n");
>> +		}
>> +
>> +		writel_relaxed(pmu->dram_type, pmu->membase + pmu->cfg->regs->dram_inf.reg);
>> +	}
>> +
>> +	clk_disable(pmu->clk);
>> +
>> +	return 0;
>> +}
> 
>> +static const struct stm32_ddr_pmu_regspec stm32_ddr_pmu_regspec_mp2 = {
>> +	.stop =		{ DDRPERFM_CTRL, CTRL_STOP },
>> +	.start =	{ DDRPERFM_CTRL, CTRL_START },
>> +	.status =	{ DDRPERFM_MP2_STATUS, MP2_STATUS_BUSY },
>> +	.clear_cnt =	{ DDRPERFM_CLR, MP2_CLR_CNT},
>> +	.clear_time =	{ DDRPERFM_CLR, MP2_CLR_TIME},
> 
> Spaces before } are missing
> There are a few others above that I'll not mention directly.

Ok thanks

> 
> 
>> +	.cfg0 =		{ DDRPERFM_MP2_CFG0 },
>> +	.cfg1 =		{ DDRPERFM_MP2_CFG1 },
>> +	.enable =	{ DDRPERFM_MP2_CFG5 },
>> +	.dram_inf =	{ DDRPERFM_MP2_DRAMINF },
>> +	.counter_time =	{ DDRPERFM_MP2_TCNT },
>> +	.counter_evt =	{
>> +				{ DDRPERFM_MP2_EVCNT(0) },
> Somewhat unusual formatting though neat I guess so fine if you
> really like it!.
> 	.counter_evt =	{
> 		{ DDRPERFM_MP2_EVCNT(0) },
> 
> would be what I'd normally expect.

I'll stick to normality, don't wanna be special here

>> +				{ DDRPERFM_MP2_EVCNT(1) },
>> +				{ DDRPERFM_MP2_EVCNT(2) },
>> +				{ DDRPERFM_MP2_EVCNT(3) },
>> +				{ DDRPERFM_MP2_EVCNT(4) },
>> +				{ DDRPERFM_MP2_EVCNT(5) },
>> +				{ DDRPERFM_MP2_EVCNT(6) },
>> +				{ DDRPERFM_MP2_EVCNT(7) },
>> +	},
>> +};
>> +
>> +static const struct stm32_ddr_pmu_cfg stm32_ddr_pmu_cfg_mp1 = {
>> +	.regs = &stm32_ddr_pmu_regspec_mp1,
>> +	.attribute = stm32_ddr_pmu_attr_groups_mp1,
>> +	.counters_nb = MP1_CNT_NB,
>> +	.evt_counters_nb = MP1_CNT_NB - 1, /* Time counter is not an event counter */
>> +	.time_cnt_idx = MP1_TIME_CNT_IDX,
>> +	.get_counter = stm32_ddr_pmu_get_event_counter_mp1,
>> +};
>> +
>> +static const struct stm32_ddr_pmu_cfg stm32_ddr_pmu_cfg_mp2 = {
>> +	.regs = &stm32_ddr_pmu_regspec_mp2,
>> +	.attribute = stm32_ddr_pmu_attr_groups_mp2,
>> +	.counters_nb = MP2_CNT_NB,
>> +	.evt_counters_nb = MP2_CNT_NB - 1, /* Time counter is an event counter */
>> +	.time_cnt_idx = MP2_TIME_CNT_IDX,
>> +	.get_counter = stm32_ddr_pmu_get_event_counter_mp2,
>> +};
>> +
>> +static const struct dev_pm_ops stm32_ddr_pmu_pm_ops = {
>> +	SET_SYSTEM_SLEEP_PM_OPS(NULL, stm32_ddr_pmu_device_resume)
>> +};
> 
> static DEFINE_SIMPLE_DEV_PM_OPS() looks appropriate here.

Indeed, Thank you

> 
> 
>> +
>> +static const struct of_device_id stm32_ddr_pmu_of_match[] = {
>> +	{
>> +		.compatible = "st,stm32mp131-ddr-pmu",
>> +		.data = &stm32_ddr_pmu_cfg_mp1
>> +	},
>> +	{
>> +		.compatible = "st,stm32mp251-ddr-pmu",
>> +		.data = &stm32_ddr_pmu_cfg_mp2
>> +	},
>> +	{ },
> 
> No comma need after terminating entry.  Nice to make it hard
> to accidentally add entries after one of these!

Yes, I'll fix it

Best regards,
Clément

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 02/16] dt-bindings: stm32: stm32mp25: add `access-controller-cell` property
  2025-07-15  3:17   ` Rob Herring
  2025-07-15  7:37     ` Gatien CHEVALLIER
@ 2025-07-15 11:47     ` Clement LE GOFFIC
  1 sibling, 0 replies; 32+ messages in thread
From: Clement LE GOFFIC @ 2025-07-15 11:47 UTC (permalink / raw)
  To: Rob Herring
  Cc: Will Deacon, Mark Rutland, Krzysztof Kozlowski, Conor Dooley,
	Maxime Coquelin, Alexandre Torgue, Philipp Zabel, Jonathan Corbet,
	Gatien Chevallier, Michael Turquette, Stephen Boyd,
	Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic,
	linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk

Hi Rob,

On 7/15/25 05:17, Rob Herring wrote:
> On Fri, Jul 11, 2025 at 04:48:54PM +0200, Clément Le Goffic wrote:
>> RCC is able to check the availability of a clock.
>> Allow to query the RCC with a firewall ID.
> 
> If it is tied to a clock, do we need another provider? We have the
> "protected clocks" thing, but that might be a bit different.

What I understand is that the "protected-clocks" list is here to flag 
clocks as protected and the access to it and its register by the kernel 
may cause the reboot of the platform.
The current qcom implementation just drop clocks so no one can access to 
it after they are registered.
For my understanding if you know why the kernel needs the information 
"this clock can't be accessed", I would be interested/

Without the STM32 RCC driver modification, if we access to the DDRPERFM 
peripheral register when the clock is secured we face the same issue, we 
end up rebooting the platform.

Our RCC peripheral is able to know if our DDR subsystem clock (that is 
shared between our DDR controller and DDRPERFM peripheral) is secured or 
not, so we can access or not to DDRPERFM register.
It is the aim of the "access-controller" related code.

Correct me if I'm wrong but to me the difference might be that the 
"protected-clocks" property is here to list in the DT clocks that can't 
be accessed and that this information is not in the hardware.

In the STM32MP25 we are able to get this information through RCC 
dedicated register. You can look at the `stm32_rcc_get_access()` 
function in drivers/clk/stm32/clk-stm32mp25.c if needed.

Best regards,
Clément

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 06/16] arm64: dts: st: add LPDDR channel to stm32mp257f-dk board
  2025-07-15  8:32     ` Clement LE GOFFIC
@ 2025-07-15 15:02       ` Rob Herring
  2025-07-21 15:44         ` Clement LE GOFFIC
  0 siblings, 1 reply; 32+ messages in thread
From: Rob Herring @ 2025-07-15 15:02 UTC (permalink / raw)
  To: Clement LE GOFFIC
  Cc: Will Deacon, Mark Rutland, Krzysztof Kozlowski, Conor Dooley,
	Maxime Coquelin, Alexandre Torgue, Philipp Zabel, Jonathan Corbet,
	Gatien Chevallier, Michael Turquette, Stephen Boyd,
	Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic,
	linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk

On Tue, Jul 15, 2025 at 10:32:09AM +0200, Clement LE GOFFIC wrote:
> Hi Rob,
> 
> Thanks for the review !
> 
> On 7/15/25 05:20, Rob Herring wrote:
> > On Fri, Jul 11, 2025 at 04:48:58PM +0200, Clément Le Goffic wrote:
> > > Add 32bits LPDDR4 channel to the stm32mp257f-dk board.
> > > 
> > > Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
> > > ---
> > >   arch/arm64/boot/dts/st/stm32mp257f-dk.dts | 7 +++++++
> > >   1 file changed, 7 insertions(+)
> > > 
> > > diff --git a/arch/arm64/boot/dts/st/stm32mp257f-dk.dts b/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
> > > index a278a1e3ce03..a97b41f14ecc 100644
> > > --- a/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
> > > +++ b/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
> > > @@ -54,6 +54,13 @@ led-blue {
> > >   		};
> > >   	};
> > > +	lpddr_channel: lpddr4-channel {
> > > +		#address-cells = <1>;
> > > +		#size-cells = <0>;
> > > +		compatible = "jedec,lpddr4-channel";
> > 
> > Not tested because this doesn't match the binding.
> 
> Hmm, I've tested with make dtbs_check and dt_binding_check and it didn't
> complain on my side.
> What I have miss ?

Oh wait, we already have a binding for that. I was confused with your 
adding "jedec,ddr4-channel". Sorry for the noise.

Rob

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 06/16] arm64: dts: st: add LPDDR channel to stm32mp257f-dk board
  2025-07-15 15:02       ` Rob Herring
@ 2025-07-21 15:44         ` Clement LE GOFFIC
  0 siblings, 0 replies; 32+ messages in thread
From: Clement LE GOFFIC @ 2025-07-21 15:44 UTC (permalink / raw)
  To: Rob Herring
  Cc: Will Deacon, Mark Rutland, Krzysztof Kozlowski, Conor Dooley,
	Maxime Coquelin, Alexandre Torgue, Philipp Zabel, Jonathan Corbet,
	Gatien Chevallier, Michael Turquette, Stephen Boyd,
	Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic,
	linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk

Hi Rob

On 7/15/25 17:02, Rob Herring wrote:
> On Tue, Jul 15, 2025 at 10:32:09AM +0200, Clement LE GOFFIC wrote:
>> Hi Rob,
>>
>> Thanks for the review !
>>
>> On 7/15/25 05:20, Rob Herring wrote:
>>> On Fri, Jul 11, 2025 at 04:48:58PM +0200, Clément Le Goffic wrote:
>>>> Add 32bits LPDDR4 channel to the stm32mp257f-dk board.
>>>>
>>>> Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
>>>> ---
>>>>    arch/arm64/boot/dts/st/stm32mp257f-dk.dts | 7 +++++++
>>>>    1 file changed, 7 insertions(+)
>>>>
>>>> diff --git a/arch/arm64/boot/dts/st/stm32mp257f-dk.dts b/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
>>>> index a278a1e3ce03..a97b41f14ecc 100644
>>>> --- a/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
>>>> +++ b/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
>>>> @@ -54,6 +54,13 @@ led-blue {
>>>>    		};
>>>>    	};
>>>> +	lpddr_channel: lpddr4-channel {
>>>> +		#address-cells = <1>;
>>>> +		#size-cells = <0>;
>>>> +		compatible = "jedec,lpddr4-channel";
>>>
>>> Not tested because this doesn't match the binding.
>>
>> Hmm, I've tested with make dtbs_check and dt_binding_check and it didn't
>> complain on my side.
>> What I have miss ?
> 
> Oh wait, we already have a binding for that. I was confused with your
> adding "jedec,ddr4-channel". Sorry for the noise.

It's fine no worries.
However, in the patch 8, I add the property "memory-channel" that is not 
in the dtschema repo and I didn't get any reviews on it.
Is it ok for you ? or maybe should we discuss it over there ?
I can try to do a PR on the dtschema thought, if it is ok.

Best regards,
Clément

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 05/16] dt-bindings: memory: add jedec,ddr[3-4]-channel binding
  2025-07-11 14:48 ` [PATCH v2 05/16] dt-bindings: memory: add jedec,ddr[3-4]-channel binding Clément Le Goffic
@ 2025-07-21 20:09   ` Rob Herring
  2025-07-22  7:35     ` Clement LE GOFFIC
  0 siblings, 1 reply; 32+ messages in thread
From: Rob Herring @ 2025-07-21 20:09 UTC (permalink / raw)
  To: Clément Le Goffic
  Cc: Will Deacon, Mark Rutland, Krzysztof Kozlowski, Conor Dooley,
	Maxime Coquelin, Alexandre Torgue, Philipp Zabel, Jonathan Corbet,
	Gatien Chevallier, Michael Turquette, Stephen Boyd,
	Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic,
	linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk

On Fri, Jul 11, 2025 at 04:48:57PM +0200, Clément Le Goffic wrote:
> Introduce as per jedec,lpddrX-channel binding, jdec,ddr[3-4]-channel
> binding.
> 
> Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
> ---
>  .../memory-controllers/ddr/jedec,ddr-channel.yaml  | 53 ++++++++++++++++++++++
>  1 file changed, 53 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,ddr-channel.yaml b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,ddr-channel.yaml
> new file mode 100644
> index 000000000000..31daa22bcd4a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,ddr-channel.yaml
> @@ -0,0 +1,53 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,ddr-channel.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: DDR channel with chip/rank topology description
> +
> +description:
> +  A DDR channel is a logical grouping of memory chips that are connected
> +  to a host system. The main purpose of this node is to describe the
> +  overall DDR topology of the system, including the amount of individual
> +  DDR chips.
> +
> +maintainers:
> +  - Clément Le Goffic <legoffic.clement@gmail.com>
> +
> +properties:
> +  compatible:
> +    enum:
> +      - jedec,ddr3-channel
> +      - jedec,ddr4-channel
> +
> +  io-width:
> +    description:
> +      The number of DQ pins in the channel. If this number is different
> +      from (a multiple of) the io-width of the DDR chip, that means that
> +      multiple instances of that type of chip are wired in parallel on this
> +      channel (with the channel's DQ pins split up between the different
> +      chips, and the CA, CS, etc. pins of the different chips all shorted
> +      together).  This means that the total physical memory controlled by a
> +      channel is equal to the sum of the densities of each rank on the
> +      connected DDR chip, times the io-width of the channel divided by
> +      the io-width of the DDR chip.
> +    enum:
> +      - 8
> +      - 16
> +      - 32
> +      - 64
> +      - 128

This is duplicating what's in jedec,lpddr-channel.yaml. Refactor or add 
to it rather than duplicating.

Is there some reason regular DDR3/4 doesn't have ranks? I'm pretty sure 
it can...

Rob

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 05/16] dt-bindings: memory: add jedec,ddr[3-4]-channel binding
  2025-07-21 20:09   ` Rob Herring
@ 2025-07-22  7:35     ` Clement LE GOFFIC
  0 siblings, 0 replies; 32+ messages in thread
From: Clement LE GOFFIC @ 2025-07-22  7:35 UTC (permalink / raw)
  To: Rob Herring
  Cc: Will Deacon, Mark Rutland, Krzysztof Kozlowski, Conor Dooley,
	Maxime Coquelin, Alexandre Torgue, Philipp Zabel, Jonathan Corbet,
	Gatien Chevallier, Michael Turquette, Stephen Boyd,
	Gabriel Fernandez, Krzysztof Kozlowski, Le Goffic,
	linux-arm-kernel, linux-perf-users, devicetree, linux-stm32,
	linux-kernel, linux-doc, linux-clk

Hi Rob,

On 7/21/25 22:09, Rob Herring wrote:
> On Fri, Jul 11, 2025 at 04:48:57PM +0200, Clément Le Goffic wrote:
>> Introduce as per jedec,lpddrX-channel binding, jdec,ddr[3-4]-channel
>> binding.
>>
>> Signed-off-by: Clément Le Goffic <clement.legoffic@foss.st.com>
>> ---
>>   .../memory-controllers/ddr/jedec,ddr-channel.yaml  | 53 ++++++++++++++++++++++
>>   1 file changed, 53 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,ddr-channel.yaml b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,ddr-channel.yaml
>> new file mode 100644
>> index 000000000000..31daa22bcd4a
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,ddr-channel.yaml
>> @@ -0,0 +1,53 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,ddr-channel.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: DDR channel with chip/rank topology description
>> +
>> +description:
>> +  A DDR channel is a logical grouping of memory chips that are connected
>> +  to a host system. The main purpose of this node is to describe the
>> +  overall DDR topology of the system, including the amount of individual
>> +  DDR chips.
>> +
>> +maintainers:
>> +  - Clément Le Goffic <legoffic.clement@gmail.com>
>> +
>> +properties:
>> +  compatible:
>> +    enum:
>> +      - jedec,ddr3-channel
>> +      - jedec,ddr4-channel
>> +
>> +  io-width:
>> +    description:
>> +      The number of DQ pins in the channel. If this number is different
>> +      from (a multiple of) the io-width of the DDR chip, that means that
>> +      multiple instances of that type of chip are wired in parallel on this
>> +      channel (with the channel's DQ pins split up between the different
>> +      chips, and the CA, CS, etc. pins of the different chips all shorted
>> +      together).  This means that the total physical memory controlled by a
>> +      channel is equal to the sum of the densities of each rank on the
>> +      connected DDR chip, times the io-width of the channel divided by
>> +      the io-width of the DDR chip.
>> +    enum:
>> +      - 8
>> +      - 16
>> +      - 32
>> +      - 64
>> +      - 128
> 
> This is duplicating what's in jedec,lpddr-channel.yaml. Refactor or add
> to it rather than duplicating.

Yes I wanted something unique as "jedec,lpddr-channel.yaml" is 
specifically for lpddr.
I think I'll refactor and rename it "jedec,memory-channel.yaml" so it is 
more generic.

> Is there some reason regular DDR3/4 doesn't have ranks? I'm pretty sure
> it can...

Yes it does but I wasn't needing it and they are not required in case of 
lpddr. It will be fixed by refactoring jedec,lpddr-channel.yaml binding.

Best regards,
Clément




^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2025-07-22  7:38 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-11 14:48 [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Clément Le Goffic
2025-07-11 14:48 ` [PATCH v2 01/16] bus: firewall: move stm32_firewall header file in include folder Clément Le Goffic
2025-07-11 14:48 ` [PATCH v2 02/16] dt-bindings: stm32: stm32mp25: add `access-controller-cell` property Clément Le Goffic
2025-07-15  3:17   ` Rob Herring
2025-07-15  7:37     ` Gatien CHEVALLIER
2025-07-15  8:19       ` Krzysztof Kozlowski
2025-07-15  8:40         ` Gatien CHEVALLIER
2025-07-15 11:47     ` Clement LE GOFFIC
2025-07-11 14:48 ` [PATCH v2 03/16] clk: stm32mp25: add firewall grant_access ops Clément Le Goffic
2025-07-11 14:48 ` [PATCH v2 04/16] arm64: dts: st: set rcc as an access-controller Clément Le Goffic
2025-07-11 14:48 ` [PATCH v2 05/16] dt-bindings: memory: add jedec,ddr[3-4]-channel binding Clément Le Goffic
2025-07-21 20:09   ` Rob Herring
2025-07-22  7:35     ` Clement LE GOFFIC
2025-07-11 14:48 ` [PATCH v2 06/16] arm64: dts: st: add LPDDR channel to stm32mp257f-dk board Clément Le Goffic
2025-07-15  3:20   ` Rob Herring
2025-07-15  8:32     ` Clement LE GOFFIC
2025-07-15 15:02       ` Rob Herring
2025-07-21 15:44         ` Clement LE GOFFIC
2025-07-11 14:48 ` [PATCH v2 07/16] arm64: dts: st: add DDR channel to stm32mp257f-ev1 board Clément Le Goffic
2025-07-11 14:49 ` [PATCH v2 08/16] dt-bindings: perf: stm32: introduce DDRPERFM dt-bindings Clément Le Goffic
2025-07-11 14:49 ` [PATCH v2 09/16] perf: stm32: introduce DDRPERFM driver Clément Le Goffic
2025-07-11 16:04   ` Jonathan Cameron
2025-07-15  9:49     ` Clement LE GOFFIC
2025-07-14 19:39   ` Dan Carpenter
2025-07-11 14:49 ` [PATCH v2 10/16] Documentation: perf: stm32: add ddrperfm support Clément Le Goffic
2025-07-11 14:49 ` [PATCH v2 11/16] MAINTAINERS: add myself as STM32 DDR PMU maintainer Clément Le Goffic
2025-07-11 14:49 ` [PATCH v2 12/16] ARM: dts: stm32: add ddrperfm on stm32mp131 Clément Le Goffic
2025-07-11 14:49 ` [PATCH v2 13/16] ARM: dts: stm32: add ddrperfm on stm32mp151 Clément Le Goffic
2025-07-11 14:49 ` [PATCH v2 14/16] arm64: dts: st: add ddrperfm on stm32mp251 Clément Le Goffic
2025-07-11 14:49 ` [PATCH v2 15/16] arm64: dts: st: support ddrperfm on stm32mp257f-dk Clément Le Goffic
2025-07-11 14:49 ` [PATCH v2 16/16] arm64: dts: st: support ddrperfm on stm32mp257f-ev1 Clément Le Goffic
2025-07-14 15:24 ` [PATCH v2 00/16] Introduce STM32 DDR PMU for STM32MP platforms Rob Herring (Arm)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).