linux-perf-users.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] Add PPMU support for Tesla FSD
       [not found] <CGME20250708103228epcas5p27886821d1ff225f2e5cdd4d948d03a66@epcas5p2.samsung.com>
@ 2025-07-08 10:32 ` Vivek Yadav
       [not found]   ` <CGME20250708103231epcas5p1b9fe52dd6ea3cdd65a5df163ba05e139@epcas5p1.samsung.com>
                     ` (5 more replies)
  0 siblings, 6 replies; 12+ messages in thread
From: Vivek Yadav @ 2025-07-08 10:32 UTC (permalink / raw)
  To: pankaj.dubey, ravi.patel, shradha.t, mturquette, sboyd, robh,
	krzk, krzk+dt, conor+dt, will, mark.rutland, s.nawrocki,
	cw00.choi, alim.akhtar, linux-fsd
  Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-perf-users, linux-samsung-soc, Vivek Yadav

The Platform Performance Measuring Unit (PPMU) is an AMBA-compliant
performance measurement tool designed to provide observability into
system-level operations. It provides performance statistics such as
as bandwidth, read and write request, transactions count for AXI masters.

FSD platform has two instances of PPMU IP in MFC. This patch series
contains PPMU clock binding definitions, device tree binding
documentation, PPMU24 driver support which configures the
PPMU24 hardware and the PPMU device tree node support
for Tesla FSD platform.

Vivek Yadav (6):
  dt-bindings: clock: Add PPMU clock definitions for FSD platform
  clk: samsung: fsd: Use clock IDs for PPMU MFC block
  dt-bindings: perf: Add devicetree binding for custom PPMU
  drivers: perf: samsung: Add PPMU driver support
  arm64: dts: fsd: Add PPMU support for MFC block of FSD SoC
  MAINTAINERS: Add maintainers for Samsung PPMU driver

 .../bindings/perf/samsung,ppmu-v2.yaml        |  62 +++
 MAINTAINERS                                   |   7 +
 arch/arm64/boot/dts/tesla/fsd-evb.dts         |   8 +
 arch/arm64/boot/dts/tesla/fsd.dtsi            |  20 +
 drivers/clk/samsung/clk-fsd.c                 |  10 +-
 drivers/perf/Kconfig                          |   2 +
 drivers/perf/Makefile                         |   1 +
 drivers/perf/samsung/Kconfig                  |  13 +
 drivers/perf/samsung/Makefile                 |   2 +
 drivers/perf/samsung/ppmu.c                   | 494 ++++++++++++++++++
 drivers/perf/samsung/ppmu_platform.c          | 338 ++++++++++++
 drivers/perf/samsung/samsung_ppmu.h           | 128 +++++
 include/dt-bindings/clock/fsd-clk.h           |   4 +
 13 files changed, 1084 insertions(+), 5 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/perf/samsung,ppmu-v2.yaml
 create mode 100644 drivers/perf/samsung/Kconfig
 create mode 100644 drivers/perf/samsung/Makefile
 create mode 100644 drivers/perf/samsung/ppmu.c
 create mode 100644 drivers/perf/samsung/ppmu_platform.c
 create mode 100644 drivers/perf/samsung/samsung_ppmu.h

-- 
2.49.0


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

* [PATCH 1/6] dt-bindings: clock: Add PPMU clock definitions for FSD platform
       [not found]   ` <CGME20250708103231epcas5p1b9fe52dd6ea3cdd65a5df163ba05e139@epcas5p1.samsung.com>
@ 2025-07-08 10:32     ` Vivek Yadav
  0 siblings, 0 replies; 12+ messages in thread
From: Vivek Yadav @ 2025-07-08 10:32 UTC (permalink / raw)
  To: pankaj.dubey, ravi.patel, shradha.t, mturquette, sboyd, robh,
	krzk, krzk+dt, conor+dt, will, mark.rutland, s.nawrocki,
	cw00.choi, alim.akhtar, linux-fsd
  Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-perf-users, linux-samsung-soc, Vivek Yadav

Add clock IDs for PPMU (Platform Performance Monitoring Unit)
associated with the MFC block.

Signed-off-by: Ravi Patel <ravi.patel@samsung.com>
Signed-off-by: Vivek Yadav <vivek.2311@samsung.com>
---
 include/dt-bindings/clock/fsd-clk.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/include/dt-bindings/clock/fsd-clk.h b/include/dt-bindings/clock/fsd-clk.h
index 3f7b64d93558..552e8bad98e0 100644
--- a/include/dt-bindings/clock/fsd-clk.h
+++ b/include/dt-bindings/clock/fsd-clk.h
@@ -125,6 +125,10 @@
 
 /* MFC */
 #define MFC_MFC_IPCLKPORT_ACLK			1
+#define MFC_PPMU_MFCD0_IPCLKPORT_ACLK		2
+#define MFC_PPMU_MFCD0_IPCLKPORT_PCLK		3
+#define MFC_PPMU_MFCD1_IPCLKPORT_ACLK		4
+#define MFC_PPMU_MFCD1_IPCLKPORT_PCLK		5
 
 /* CAM_CSI */
 #define CAM_CSI0_0_IPCLKPORT_I_ACLK		1
-- 
2.49.0


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

* [PATCH 2/6] clk: samsung: fsd: Use clock IDs for PPMU MFC block
       [not found]   ` <CGME20250708103234epcas5p1a92b0b57315f6e81c906fedcc232c279@epcas5p1.samsung.com>
@ 2025-07-08 10:32     ` Vivek Yadav
  0 siblings, 0 replies; 12+ messages in thread
From: Vivek Yadav @ 2025-07-08 10:32 UTC (permalink / raw)
  To: pankaj.dubey, ravi.patel, shradha.t, mturquette, sboyd, robh,
	krzk, krzk+dt, conor+dt, will, mark.rutland, s.nawrocki,
	cw00.choi, alim.akhtar, linux-fsd
  Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-perf-users, linux-samsung-soc, Vivek Yadav

Use PPMU clock ID macros for PPMU MFC gate clocks.

Signed-off-by: Ravi Patel <ravi.patel@samsung.com>
Signed-off-by: Vivek Yadav <vivek.2311@samsung.com>
---
 drivers/clk/samsung/clk-fsd.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/samsung/clk-fsd.c b/drivers/clk/samsung/clk-fsd.c
index 9a6006c298c2..f80d35feb3f7 100644
--- a/drivers/clk/samsung/clk-fsd.c
+++ b/drivers/clk/samsung/clk-fsd.c
@@ -88,7 +88,7 @@
 #define CLKS_NR_FSYS0		(FSYS0_DOUT_FSYS0_PERIBUS_GRP + 1)
 #define CLKS_NR_FSYS1		(PCIE_LINK1_IPCLKPORT_SLV_ACLK + 1)
 #define CLKS_NR_IMEM		(IMEM_TMU_GT_IPCLKPORT_I_CLK_TS + 1)
-#define CLKS_NR_MFC		(MFC_MFC_IPCLKPORT_ACLK + 1)
+#define CLKS_NR_MFC		(MFC_PPMU_MFCD1_IPCLKPORT_PCLK + 1)
 #define CLKS_NR_CAM_CSI		(CAM_CSI2_3_IPCLKPORT_I_ACLK + 1)
 
 static const unsigned long cmu_clk_regs[] __initconst = {
@@ -1519,13 +1519,13 @@ static const struct samsung_gate_clock mfc_gate_clks[] __initconst = {
 	     GAT_MFC_NS_BRDG_MFC_IPCLKPORT_CLK__PMFC__CLK_MFC_D, 21, CLK_IGNORE_UNUSED, 0),
 	GATE(0, "mfc_ns_brdg_mfc_ipclkport_clk__pmfc__clk_mfc_p", "mout_mfc_busp",
 	     GAT_MFC_NS_BRDG_MFC_IPCLKPORT_CLK__PMFC__CLK_MFC_P, 21, CLK_IGNORE_UNUSED, 0),
-	GATE(0, "mfc_ppmu_mfcd0_ipclkport_aclk", "mout_mfc_busd",
+	GATE(MFC_PPMU_MFCD0_IPCLKPORT_ACLK, "mfc_ppmu_mfcd0_ipclkport_aclk", "mout_mfc_busd",
 	     GAT_MFC_PPMU_MFCD0_IPCLKPORT_ACLK, 21, CLK_IGNORE_UNUSED, 0),
-	GATE(0, "mfc_ppmu_mfcd0_ipclkport_pclk", "mout_mfc_busp",
+	GATE(MFC_PPMU_MFCD0_IPCLKPORT_PCLK, "mfc_ppmu_mfcd0_ipclkport_pclk", "mout_mfc_busp",
 	     GAT_MFC_PPMU_MFCD0_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
-	GATE(0, "mfc_ppmu_mfcd1_ipclkport_aclk", "mout_mfc_busd",
+	GATE(MFC_PPMU_MFCD1_IPCLKPORT_ACLK, "mfc_ppmu_mfcd1_ipclkport_aclk", "mout_mfc_busd",
 	     GAT_MFC_PPMU_MFCD1_IPCLKPORT_ACLK, 21, CLK_IGNORE_UNUSED, 0),
-	GATE(0, "mfc_ppmu_mfcd1_ipclkport_pclk", "mout_mfc_busp",
+	GATE(MFC_PPMU_MFCD1_IPCLKPORT_PCLK, "mfc_ppmu_mfcd1_ipclkport_pclk", "mout_mfc_busp",
 	     GAT_MFC_PPMU_MFCD1_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
 	GATE(0, "mfc_sysreg_mfc_ipclkport_pclk", "mout_mfc_busp",
 	     GAT_MFC_SYSREG_MFC_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
-- 
2.49.0


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

* [PATCH 3/6] dt-bindings: perf: Add devicetree binding for custom PPMU
       [not found]   ` <CGME20250708103237epcas5p1c4c5d7a5f43c0c88317e74d2f2458a1b@epcas5p1.samsung.com>
@ 2025-07-08 10:32     ` Vivek Yadav
  2025-07-09 14:01       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 12+ messages in thread
From: Vivek Yadav @ 2025-07-08 10:32 UTC (permalink / raw)
  To: pankaj.dubey, ravi.patel, shradha.t, mturquette, sboyd, robh,
	krzk, krzk+dt, conor+dt, will, mark.rutland, s.nawrocki,
	cw00.choi, alim.akhtar, linux-fsd
  Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-perf-users, linux-samsung-soc, Vivek Yadav

Add the dt-binding documentation for the Samsung specific
Platform Performance Monitoring Unit (PPMU) driver which provides
performance statistics for AXI bus masters such as MFC.

Signed-off-by: Ravi Patel <ravi.patel@samsung.com>
Signed-off-by: Vivek Yadav <vivek.2311@samsung.com>
---
 .../bindings/perf/samsung,ppmu-v2.yaml        | 62 +++++++++++++++++++
 1 file changed, 62 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/perf/samsung,ppmu-v2.yaml

diff --git a/Documentation/devicetree/bindings/perf/samsung,ppmu-v2.yaml b/Documentation/devicetree/bindings/perf/samsung,ppmu-v2.yaml
new file mode 100644
index 000000000000..d137d06b7034
--- /dev/null
+++ b/Documentation/devicetree/bindings/perf/samsung,ppmu-v2.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/perf/samsung,ppmu-v2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung PPMU (Platform Performance Monitoring Unit)
+
+maintainers:
+  - Vivek Yadav <vivek.2311@samsung.com>
+  - Ravi Patel <ravi.patel@samsung.com>
+
+description:
+  PPMU (Platform Performance Monitoring Unit) provides performance statistics
+  such as bandwidth, read and write request, transactions count for AXI masters
+  like MFC.
+
+properties:
+  compatible:
+    const: samsung,ppmu-v2
+
+  reg:
+    maxItems: 1
+    description: Memory-mapped register address
+
+  clocks:
+    items:
+      - description: AXI bus clock
+      - description: Peripheral clock
+
+  clock-names:
+    items:
+      - const: aclk
+      - const: pclk
+
+  interrupts:
+    items:
+      - description: Overflow interrupt for Counters
+      - description: Conditional Interrupt Generation (CIG)
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/fsd-clk.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    ppmu@12840000 {
+        compatible = "samsung,ppmu-v2";
+        reg = <0x12840000 0x1000>;
+        interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clock_mfc MFC_PPMU_MFCD0_IPCLKPORT_ACLK>,
+                 <&clock_mfc MFC_PPMU_MFCD0_IPCLKPORT_PCLK>;
+        clock-names = "aclk", "pclk";
+     };
-- 
2.49.0


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

* [PATCH 4/6] drivers: perf: samsung: Add PPMU driver support
       [not found]   ` <CGME20250708103240epcas5p336539d4c3a1fb489708c61f9aae6bfa8@epcas5p3.samsung.com>
@ 2025-07-08 10:32     ` Vivek Yadav
  2025-07-09 14:05       ` Krzysztof Kozlowski
  2025-07-11 14:45       ` Jonathan Cameron
  0 siblings, 2 replies; 12+ messages in thread
From: Vivek Yadav @ 2025-07-08 10:32 UTC (permalink / raw)
  To: pankaj.dubey, ravi.patel, shradha.t, mturquette, sboyd, robh,
	krzk, krzk+dt, conor+dt, will, mark.rutland, s.nawrocki,
	cw00.choi, alim.akhtar, linux-fsd
  Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-perf-users, linux-samsung-soc, Vivek Yadav

Add Samsung PPMU driver support in the Linux perf subsystem.

PPMU24 driver configures the PPMU24 hardware which is found
in the Samsung SoCs like Tesla FSD.

Signed-off-by: Ravi Patel <ravi.patel@samsung.com>
Signed-off-by: Vivek Yadav <vivek.2311@samsung.com>
---
 drivers/perf/Kconfig                 |   2 +
 drivers/perf/Makefile                |   1 +
 drivers/perf/samsung/Kconfig         |  13 +
 drivers/perf/samsung/Makefile        |   2 +
 drivers/perf/samsung/ppmu.c          | 494 +++++++++++++++++++++++++++
 drivers/perf/samsung/ppmu_platform.c | 338 ++++++++++++++++++
 drivers/perf/samsung/samsung_ppmu.h  | 128 +++++++
 7 files changed, 978 insertions(+)
 create mode 100644 drivers/perf/samsung/Kconfig
 create mode 100644 drivers/perf/samsung/Makefile
 create mode 100644 drivers/perf/samsung/ppmu.c
 create mode 100644 drivers/perf/samsung/ppmu_platform.c
 create mode 100644 drivers/perf/samsung/samsung_ppmu.h

diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index 4e268de351c4..0852bcae6cd2 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -271,6 +271,8 @@ source "drivers/perf/arm_cspmu/Kconfig"
 
 source "drivers/perf/amlogic/Kconfig"
 
+source "drivers/perf/samsung/Kconfig"
+
 config CXL_PMU
 	tristate "CXL Performance Monitoring Unit"
 	depends on CXL_BUS
diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
index de71d2574857..5f764d9fc601 100644
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -33,3 +33,4 @@ obj-$(CONFIG_DWC_PCIE_PMU) += dwc_pcie_pmu.o
 obj-$(CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU) += arm_cspmu/
 obj-$(CONFIG_MESON_DDR_PMU) += amlogic/
 obj-$(CONFIG_CXL_PMU) += cxl_pmu.o
+obj-$(CONFIG_SAMSUNG_PPMU24) += samsung/
diff --git a/drivers/perf/samsung/Kconfig b/drivers/perf/samsung/Kconfig
new file mode 100644
index 000000000000..2088e2b7299d
--- /dev/null
+++ b/drivers/perf/samsung/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Programmable Performance Monitoring Unit (PPMU) driver
+#
+
+config SAMSUNG_PPMU24
+	tristate "Samsung PPMU24 drivers"
+	depends on ARM64 && ARCH_EXYNOS
+	help
+	 The Platform Performance Measuring Unit (PPMU) is an AMBA-compliant
+	 performance measurement tool designed to provide observability into
+	 system-level operations. It provides performance statistics such as
+	 as bandwidth, read and write request, transactions count for AXI masters.
diff --git a/drivers/perf/samsung/Makefile b/drivers/perf/samsung/Makefile
new file mode 100644
index 000000000000..c9ed1e1a986e
--- /dev/null
+++ b/drivers/perf/samsung/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_SAMSUNG_PPMU24) += ppmu_platform.o ppmu.o
diff --git a/drivers/perf/samsung/ppmu.c b/drivers/perf/samsung/ppmu.c
new file mode 100644
index 000000000000..cacb9cdec79f
--- /dev/null
+++ b/drivers/perf/samsung/ppmu.c
@@ -0,0 +1,494 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Samsung Platform Performance Measuring Unit (PPMU) driver
+ *
+ * Copyright (c) 2024-25 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Vivek Yadav <vivek.2311@samsung.com>
+ *          Ravi Patel <ravi.patel@samsung.com>
+ */
+
+#include <linux/idr.h>
+#include <linux/of.h>
+#include <linux/perf_event.h>
+#include <linux/platform_device.h>
+#include "samsung_ppmu.h"
+
+#define PPMU_CLEAR_FLAG				(GENMASK(3, 0) | BIT(31))
+
+#define PPMU_PMCNT3_HIGH_VAL			(3)
+#define PPMU_PMCNT2_HIGH_VAL			(2)
+#define PPMU_RESET_CCNT				BIT(2)
+#define PPMU_RESET_PMCNT			BIT(1)
+
+#define PPMU_PMNC_OP_MODE_MASK			(GENMASK(21, 20))
+#define PPMU_PMNC_OP_MODE_OFF			(20)
+#define PPMU_MANUAL_MODE_VAL			(0x0)
+#define PPMU_PMNC_GLB_CNT_EN_VAL		(BIT(0))
+#define PPMU_PMNC_RESET_PMCNT_VAL		(BIT(1))
+#define PPMU_PMNC_RESET_CCNT_VAL		(BIT(2))
+
+#define PPMU_V24_IDENTIFIER			(0x45)
+
+#define PPMU_CCNT_IDX				(4)
+#define PPMU_CCNT_POS_OFF			(31)
+#define PPMU_VERSION_CHECK			(GENMASK(19, 12))
+
+#define PPMU_SM_ENABLE_ALL_CNT			(0xf)
+#define PPMU_ENABLE_CCNT			BIT(31)
+#define PPMU_FILTER_MASK			(0x7)
+
+/* ID of event type */
+enum {
+	PPMU_EVENT_READ_CHANNEL_ACTIVE		= (0x00),
+	PPMU_EVENT_WRITE_CHANNEL_ACTIVE		= (0x01),
+	PPMU_EVENT_READ_REQUEST			= (0x02),
+	PPMU_EVENT_WRITE_REQUEST		= (0x03),
+	PPMU_EVENT_READ_DATA			= (0x04),
+	PPMU_EVENT_WRITE_DATA			= (0x05),
+	PPMU_EVENT_WRITE_RESPONSE		= (0x06),
+	PPMU_EVENT_LAST_READ_DATA		= (0x07),
+	PPMU_EVENT_LAST_WRITE_DATA		= (0x08),
+	PPMU_EVENT_READ_REQUEST_BOLCKING	= (0x10),
+	PPMU_EVENT_WRITE_REQUEST_BOLCKING	= (0x11),
+	PPMU_EVENT_READ_DATA_BLOCKING		= (0x12),
+	PPMU_EVENT_WRITE_DATA_BLOCKING		= (0x13),
+	PPMU_EVENT_WRITE_RESPONSE_BLOCKING	= (0x14),
+	PPMU_EVENT_READ_BURST_LENGTH		= (0x2a),
+	PPMU_EVENT_WRITE_BURST_LENGTH		= (0x2b),
+	PPMU_EVENT_CCNT				= (0xfe),
+	PPMU_EVENT_MAX				= (0xff),
+};
+
+/* Register offsets */
+enum ppmu_reg {
+	PPMU_VERSION				= (0x0000),
+	PPMU_PMNC				= (0x0004),
+	PPMU_CNTENS				= (0x0008),
+	PPMU_CNTENC				= (0x000c),
+	PPMU_INTENS				= (0x0010),
+	PPMU_INTENC				= (0x0014),
+	PPMU_FLAG				= (0x0018),
+	PPMU_CIG_CFG0				= (0x001c),
+	PPMU_CIG_CFG1				= (0x0020),
+	PPMU_CIG_CFG2				= (0x0024),
+	PPMU_CIG_RESULT				= (0x0028),
+	PPMU_CNT_RESET				= (0x002c),
+	PPMU_CNT_AUTO				= (0x0030),
+	PPMU_PMCNT0				= (0x0034),
+	PPMU_PMCNT1				= (0x0038),
+	PPMU_PMCNT2				= (0x003c),
+	PPMU_PMCNT3_LOW				= (0x0040),
+	PPMU_PMCNT3_HIGH			= (0x0044),
+	PPMU_CCNT				= (0x0048),
+	PPMU_PMCNT2_HIGH			= (0x0054),
+	PPMU_CONFIG_INFO			= (0X005c),
+	PPMU_INTERRUPT_TEST			= (0x0060),
+	PPMU_EVENT_EV0_TYPE			= (0x0200),
+	PPMU_EVENT_EV1_TYPE			= (0x0204),
+	PPMU_EVENT_EV2_TYPE			= (0x0208),
+	PPMU_EVENT_EV3_TYPE			= (0x020c),
+	PPMU_EVENT_SM_ID_MASK			= (0x0220),
+	PPMU_EVENT_SM_ID_VALUE			= (0x0224),
+	PPMU_EVENT_SM_ID_A			= (0x0228),
+	PPMU_EVENT_SM_OTHERS_V			= (0x022c),
+	PPMU_EVENT_SM_OTHERS_A			= (0x0230),
+	PPMU_EVENT_SAMPLE_RD_ID_MASK		= (0x0234),
+	PPMU_EVENT_SAMPLE_RD_ID_VALUE		= (0x0238),
+	PPMU_EVENT_SAMPLE_WR_ID_MASK		= (0x023c),
+	PPMU_EVENT_SAMPLE_WD_ID_VALUE		= (0x0240),
+	PPMU_EVENT_AXI_CH_TYPE			= (0x0244),
+	PPMU_EVENT_MO_INFO			= (0x0250),
+	PPMU_EVENT_MO_INFO_SM_ID		= (0x0254),
+	PPMU_EVENT_MO_INFO_SAMPLE		= (0x0258),
+	PPMU_EVENT_IMPRECISE_ERR		= (0x0260),
+};
+
+static const u32 ppmu_pmcnt_offset[PPMU_MAX_COUNTERS][2] = {
+	{ PPMU_PMCNT0,		PPMU_EVENT_EV0_TYPE },
+	{ PPMU_PMCNT1,		PPMU_EVENT_EV1_TYPE },
+	{ PPMU_PMCNT2,		PPMU_EVENT_EV2_TYPE },
+	{ PPMU_PMCNT3_LOW,	PPMU_EVENT_EV3_TYPE },
+	{ PPMU_CCNT,		0 },
+};
+
+static DEFINE_IDR(my_idr);
+
+static void samsung_ppmu_write_evtype(struct samsung_ppmu *s_ppmu,
+				      int idx, u32 type)
+{
+	/* Configure event */
+	if (idx != PPMU_CCNT_IDX)
+		writel(type, s_ppmu->base + ppmu_pmcnt_offset[idx][1]);
+}
+
+static int samsung_ppmu_get_event_idx(struct perf_event *event)
+{
+	struct samsung_ppmu *samsung_ppmu = to_samsung_ppmu(event->pmu);
+	unsigned long *used_mask = samsung_ppmu->pmu_events.used_mask;
+	u32 num_counters = samsung_ppmu->num_counters;
+	DECLARE_BITMAP(buf, PPMU_MAX_COUNTERS);
+	int idx;
+
+	if (event->attr.config == PPMU_EVENT_CCNT)
+		*buf = *used_mask | (~BIT(PPMU_CCNT_IDX));
+	else
+		*buf = *used_mask;
+
+	idx = find_first_zero_bit(buf, num_counters);
+	if (idx == num_counters)
+		return -EAGAIN;
+
+	set_bit(idx, used_mask);
+
+	return idx;
+}
+
+static u64 samsung_ppmu_get_read_counter(struct samsung_ppmu *s_ppmu,
+					 struct hw_perf_event *hwc)
+{
+	u64 counter_val, prev_overflow_val;
+	u64 high_val = 0;
+
+	counter_val = (u64)readl(s_ppmu->base + ppmu_pmcnt_offset[hwc->idx][0]);
+	prev_overflow_val = (u64)s_ppmu->counter_overflow[hwc->idx] << 32;
+
+	/*
+	 * PMCNT2 and PMCNT3 are 40-bit counters
+	 * its value are divided in two 32-bit registers
+	 */
+	if (hwc->idx == PPMU_PMCNT3_HIGH_VAL || hwc->idx == PPMU_PMCNT2_HIGH_VAL) {
+		prev_overflow_val = prev_overflow_val << 8;
+
+		if (hwc->idx == PPMU_PMCNT3_HIGH_VAL)
+			high_val = (u64)(readl(s_ppmu->base + PPMU_PMCNT3_HIGH) & 0xFF);
+		else
+			high_val = (u64)(readl(s_ppmu->base + PPMU_PMCNT2_HIGH) & 0xFF);
+	}
+
+	counter_val = counter_val + (high_val << 32);
+
+	/* Clear overflow status */
+	s_ppmu->counter_overflow[hwc->idx] = 0;
+
+	/* Read previous counter */
+	s_ppmu->prev_counter[hwc->idx] = counter_val;
+
+	return (counter_val | prev_overflow_val);
+}
+
+static void samsung_ppmu_get_enable_counter(struct samsung_ppmu *s_ppmu,
+					    struct hw_perf_event *hwc)
+{
+	u32 val;
+	int idx = hwc->idx;
+
+	if (idx == PPMU_CCNT_IDX)
+		idx = PPMU_CCNT_POS_OFF;
+
+	/* Enabling counters */
+	writel(BIT(idx), s_ppmu->base + PPMU_CNTENS);
+
+	/* Enabling interrupt */
+	writel(BIT(idx), s_ppmu->base + PPMU_INTENS);
+
+	/* Manual mode enabled */
+	val = readl(s_ppmu->base + PPMU_PMNC);
+	val &= (~PPMU_PMNC_OP_MODE_MASK);
+	val |= (PPMU_MANUAL_MODE_VAL << PPMU_PMNC_OP_MODE_OFF);
+	writel(val, s_ppmu->base + PPMU_PMNC);
+}
+
+static void samsung_ppmu_get_disable_counter(struct samsung_ppmu *s_ppmu,
+					     struct hw_perf_event *hwc)
+{
+	int idx = hwc->idx;
+
+	if (idx == PPMU_CCNT_IDX)
+		idx = PPMU_CCNT_POS_OFF;
+
+	/* Disabling interrupt */
+	writel(BIT(idx), s_ppmu->base + PPMU_INTENC);
+
+	/* Disabling counter */
+	writel(BIT(idx), s_ppmu->base + PPMU_CNTENC);
+
+	/* Reset counter */
+	writel(BIT(idx), s_ppmu->base + PPMU_CNT_RESET);
+}
+
+static void samsung_ppmu_get_start_counters(struct samsung_ppmu *s_ppmu)
+{
+	u32 val;
+
+	/* Clearing all overflow status */
+	writel(PPMU_CLEAR_FLAG, s_ppmu->base + PPMU_FLAG);
+
+	/* Resetting all counters */
+	val = readl(s_ppmu->base + PPMU_PMNC);
+	val |= (PPMU_PMNC_RESET_PMCNT_VAL | PPMU_PMNC_RESET_CCNT_VAL);
+	writel(val, s_ppmu->base + PPMU_PMNC);
+
+	/* Start counters */
+	val = readl(s_ppmu->base + PPMU_PMNC);
+	val |= PPMU_PMNC_GLB_CNT_EN_VAL;
+	writel(val, s_ppmu->base + PPMU_PMNC);
+
+	s_ppmu->status = PPMU_START;
+}
+
+static void samsung_ppmu_get_stop_counters(struct samsung_ppmu *s_ppmu)
+{
+	u32 val;
+
+	/* Stop counters */
+	val = readl(s_ppmu->base + PPMU_PMNC);
+	val &= (~PPMU_PMNC_GLB_CNT_EN_VAL);
+	writel(val, s_ppmu->base + PPMU_PMNC);
+
+	s_ppmu->status = PPMU_STOP;
+}
+
+static u32 samsung_ppmu_get_int_status(struct samsung_ppmu *s_ppmu)
+{
+	u32 regvalue, i;
+
+	/* Read status register */
+	regvalue = readl(s_ppmu->base + PPMU_FLAG);
+
+	for (i = 0; i < PPMU_MAX_COUNTERS; i++) {
+		if (regvalue & BIT(i))
+			s_ppmu->counter_overflow[i] += 1;
+	}
+
+	if (regvalue & BIT(PPMU_CCNT_POS_OFF)) {
+		s_ppmu->counter_overflow[PPMU_CCNT_IDX] += 1;
+		regvalue &= (~BIT(PPMU_CCNT_POS_OFF));
+		regvalue |= BIT(PPMU_CCNT_IDX);
+	}
+
+	return regvalue;
+}
+
+static void samsung_ppmu_clear_int_status(struct samsung_ppmu *s_ppmu, int idx)
+{
+	if (idx == PPMU_CCNT_IDX)
+		idx = PPMU_CCNT_POS_OFF;
+
+	/* Clear the interrupt status */
+	writel(BIT(idx), s_ppmu->base + PPMU_FLAG);
+}
+
+static struct attribute *samsung_ppmu_format_attr[] = {
+	SAMSUNG_PPMU_FORMAT_ATTR(event, "config:0-7"),
+	NULL
+};
+
+static const struct attribute_group samsung_ppmu_format_group = {
+	.name = "format",
+	.attrs = samsung_ppmu_format_attr,
+};
+
+static struct attribute *samsung_ppmu_events_attr[] = {
+	SAMSUNG_PPMU_EVENT_ATTR(rd_channel_active,	PPMU_EVENT_READ_CHANNEL_ACTIVE),
+	SAMSUNG_PPMU_EVENT_ATTR(wr_channel_active,	PPMU_EVENT_WRITE_CHANNEL_ACTIVE),
+	SAMSUNG_PPMU_EVENT_ATTR(read_request,		PPMU_EVENT_READ_REQUEST),
+	SAMSUNG_PPMU_EVENT_ATTR(write_request,		PPMU_EVENT_WRITE_REQUEST),
+	SAMSUNG_PPMU_EVENT_ATTR(read_data,		PPMU_EVENT_READ_DATA),
+	SAMSUNG_PPMU_EVENT_ATTR(write_data,		PPMU_EVENT_WRITE_DATA),
+	SAMSUNG_PPMU_EVENT_ATTR(wr_response,		PPMU_EVENT_WRITE_RESPONSE),
+	SAMSUNG_PPMU_EVENT_ATTR(last_rd_data,		PPMU_EVENT_LAST_READ_DATA),
+	SAMSUNG_PPMU_EVENT_ATTR(last_wr_data,		PPMU_EVENT_LAST_WRITE_DATA),
+	SAMSUNG_PPMU_EVENT_ATTR(rd_request_blk,		PPMU_EVENT_READ_REQUEST_BOLCKING),
+	SAMSUNG_PPMU_EVENT_ATTR(wr_request_blk,		PPMU_EVENT_WRITE_REQUEST_BOLCKING),
+	SAMSUNG_PPMU_EVENT_ATTR(rd_data_blk,		PPMU_EVENT_READ_DATA_BLOCKING),
+	SAMSUNG_PPMU_EVENT_ATTR(wr_data_blk,		PPMU_EVENT_WRITE_DATA_BLOCKING),
+	SAMSUNG_PPMU_EVENT_ATTR(wr_response_blk,	PPMU_EVENT_WRITE_RESPONSE_BLOCKING),
+	SAMSUNG_PPMU_EVENT_ATTR(rd_burst_length,	PPMU_EVENT_READ_BURST_LENGTH),
+	SAMSUNG_PPMU_EVENT_ATTR(wr_burst_length,	PPMU_EVENT_WRITE_BURST_LENGTH),
+	SAMSUNG_PPMU_EVENT_ATTR(ccnt,			PPMU_EVENT_CCNT),
+	NULL
+};
+
+static const struct attribute_group samsung_ppmu_events_group = {
+	.name = "events",
+	.attrs = samsung_ppmu_events_attr,
+};
+
+struct device_attribute dev_attr_cpumask =
+	__ATTR(cpumask, 0444, samsung_ppmu_cpumask_sysfs_show, NULL);
+
+static struct attribute *samsung_ppmu_cpumask_attrs[] = {
+	&dev_attr_cpumask.attr,
+	NULL,
+};
+
+static const struct attribute_group samsung_ppmu_cpumask_attr_group = {
+	.attrs = samsung_ppmu_cpumask_attrs,
+};
+
+static struct device_attribute samsung_ppmu_identifier_attr =
+	__ATTR(identifier, 0444, samsung_ppmu_identifier_attr_show, NULL);
+
+static struct attribute *samsung_ppmu_identifier_attrs[] = {
+	&samsung_ppmu_identifier_attr.attr,
+	NULL
+};
+
+static const struct attribute_group samsung_ppmu_identifier_group = {
+	.attrs = samsung_ppmu_identifier_attrs,
+};
+
+static const struct attribute_group *samsung_ppmu_v24_attr_groups[] = {
+	&samsung_ppmu_format_group,
+	&samsung_ppmu_events_group,
+	&samsung_ppmu_cpumask_attr_group,
+	&samsung_ppmu_identifier_group,
+	NULL
+};
+
+static struct samsung_ppmu_drv_data samsung_ppmu_v24_data = {
+	.ppmu_attr_group = samsung_ppmu_v24_attr_groups
+};
+
+static const struct samsung_ppmu_ops samsung_ppmu_plat_ops = {
+	.write_evtype		= samsung_ppmu_write_evtype,
+	.get_event_idx		= samsung_ppmu_get_event_idx,
+	.read_counter		= samsung_ppmu_get_read_counter,
+	.enable_counter		= samsung_ppmu_get_enable_counter,
+	.disable_counter	= samsung_ppmu_get_disable_counter,
+	.start_counters		= samsung_ppmu_get_start_counters,
+	.stop_counters		= samsung_ppmu_get_stop_counters,
+	.get_int_status		= samsung_ppmu_get_int_status,
+	.clear_int_status	= samsung_ppmu_clear_int_status,
+};
+
+static int ppmu_clock_init(struct samsung_ppmu *s_ppmu)
+{
+	int ret = 0;
+	struct device *dev = s_ppmu->dev;
+
+	s_ppmu->clks[PPMU_ACLK].id = "aclk";
+	s_ppmu->clks[PPMU_PCLK].id = "pclk";
+
+	ret = devm_clk_bulk_get(dev, PPMU_CLK_COUNT, s_ppmu->clks);
+	if (ret) {
+		dev_err(dev, "Failed to get clocks. Err %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_bulk_prepare_enable(PPMU_CLK_COUNT, s_ppmu->clks);
+	if (ret)
+		dev_err(dev, "Clock enable failed. Err %d\n", ret);
+
+	return ret;
+}
+
+static int samsung_ppmu_probe(struct platform_device *pdev)
+{
+	struct samsung_ppmu *s_ppmu;
+	struct device *dev = &pdev->dev;
+	u32 version;
+	char *name;
+	int ret;
+
+	s_ppmu = devm_kzalloc(dev, sizeof(*s_ppmu), GFP_KERNEL);
+	if (!s_ppmu)
+		return -ENOMEM;
+
+	s_ppmu->dev = &pdev->dev;
+
+	s_ppmu->id = idr_alloc(&my_idr, dev, 0, 2, GFP_KERNEL);
+	if (s_ppmu->id < 0) {
+		dev_err(dev, "Failed to allocate ID dynamically\n");
+		return s_ppmu->id;
+	}
+
+	/* Register base address */
+	s_ppmu->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(s_ppmu->base)) {
+		dev_err(dev, "IO remap failed\n");
+		return PTR_ERR(s_ppmu->base);
+	}
+
+	/* Register IRQ */
+	ret = samsung_ppmu_init_irq(s_ppmu, pdev);
+	if (ret)
+		return ret;
+
+	s_ppmu->check_event = PPMU_EVENT_MAX;
+	s_ppmu->num_counters = PPMU_MAX_COUNTERS;
+	s_ppmu->on_cpu = 0;
+	s_ppmu->identifier = PPMU_V24_IDENTIFIER;
+
+	s_ppmu->ppmu_data = device_get_match_data(&pdev->dev);
+	if (!s_ppmu->ppmu_data) {
+		dev_err(&pdev->dev, "No matching device data found\n");
+		return -ENODEV;
+	}
+
+	/* Register PPMU driver ops */
+	s_ppmu->pmu_events.attr_groups = s_ppmu->ppmu_data->ppmu_attr_group;
+	s_ppmu->ops = &samsung_ppmu_plat_ops;
+
+	/* Set private data to platform_device structure */
+	platform_set_drvdata(pdev, s_ppmu);
+
+	/* Initialize the PPMU */
+	samsung_ppmu_init(s_ppmu, THIS_MODULE);
+
+	ret = ppmu_clock_init(s_ppmu);
+	if (ret)
+		return ret;
+
+	version = readl(s_ppmu->base + PPMU_VERSION);
+	version &= PPMU_VERSION_CHECK;
+	version >>= 12;
+	s_ppmu->samsung_ppmu_version = version;
+
+	name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "ppmu_v_%x_%d", version, s_ppmu->id);
+	if (!name)
+		return -ENOMEM;
+
+	ret = perf_pmu_register(&s_ppmu->pmu, name, -1);
+	if (ret) {
+		clk_bulk_disable_unprepare(PPMU_CLK_COUNT, s_ppmu->clks);
+		dev_err(dev, "Failed to register PPMU in perf. Err %d\n", ret);
+	}
+
+	return ret;
+}
+
+static void samsung_ppmu_remove(struct platform_device *pdev)
+{
+	struct samsung_ppmu *s_ppmu = platform_get_drvdata(pdev);
+
+	clk_bulk_disable_unprepare(PPMU_CLK_COUNT, s_ppmu->clks);
+
+	perf_pmu_unregister(&s_ppmu->pmu);
+
+	idr_remove(&my_idr, s_ppmu->id);
+}
+
+static const struct of_device_id ppmu_of_match[] = {
+	{ .compatible = "samsung,ppmu-v2", .data = &samsung_ppmu_v24_data },
+	{}
+};
+MODULE_DEVICE_TABLE(of, ppmu_of_match);
+
+static struct platform_driver samsung_ppmu_driver = {
+	.probe = samsung_ppmu_probe,
+	.remove = samsung_ppmu_remove,
+	.driver	= {
+		.name = "samsung-ppmu",
+		.of_match_table	= ppmu_of_match,
+	},
+};
+
+module_platform_driver(samsung_ppmu_driver);
+
+MODULE_ALIAS("perf:samsung-ppmu");
+MODULE_DESCRIPTION("Samsung Platform Performance Measuring Unit (PPMU) driver");
+MODULE_AUTHOR("Vivek Yadav <vivek.2311@samsung.com>");
+MODULE_AUTHOR("Ravi Patel <ravi.patel@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/perf/samsung/ppmu_platform.c b/drivers/perf/samsung/ppmu_platform.c
new file mode 100644
index 000000000000..ee11311d5a61
--- /dev/null
+++ b/drivers/perf/samsung/ppmu_platform.c
@@ -0,0 +1,338 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Samsung Platform Performance Measuring Unit (PPMU) core file
+ *
+ * Copyright (c) 2024-25 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Vivek Yadav <vivek.2311@samsung.com>
+ *          Ravi Patel <ravi.patel@samsung.com>
+ */
+
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/perf_event.h>
+#include "samsung_ppmu.h"
+
+/*
+ * PMU format attributes
+ */
+ssize_t samsung_ppmu_format_sysfs_show(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	struct dev_ext_attribute *eattr;
+
+	eattr = container_of(attr, struct dev_ext_attribute, attr);
+
+	return sysfs_emit(buf, "%s\n", (char *)eattr->var);
+}
+EXPORT_SYMBOL_GPL(samsung_ppmu_format_sysfs_show);
+
+/*
+ * PMU event attributes
+ */
+ssize_t samsung_ppmu_event_sysfs_show(struct device *dev,
+				      struct device_attribute *attr, char *page)
+{
+	struct dev_ext_attribute *eattr;
+
+	eattr = container_of(attr, struct dev_ext_attribute, attr);
+
+	return sysfs_emit(page, "config=0x%lx\n", (unsigned long)eattr->var);
+}
+EXPORT_SYMBOL_GPL(samsung_ppmu_event_sysfs_show);
+
+/*
+ * sysfs cpumask attributes. For PPMU, we only have a single CPU to show
+ */
+ssize_t samsung_ppmu_cpumask_sysfs_show(struct device *dev,
+					struct device_attribute *attr, char *buf)
+{
+	struct samsung_ppmu *samsung_ppmu = to_samsung_ppmu(dev_get_drvdata(dev));
+
+	return sysfs_emit(buf, "%d\n", samsung_ppmu->on_cpu);
+}
+EXPORT_SYMBOL_GPL(samsung_ppmu_cpumask_sysfs_show);
+
+ssize_t samsung_ppmu_identifier_attr_show(struct device *dev,
+					  struct device_attribute *attr,
+					  char *page)
+{
+	struct samsung_ppmu *samsung_ppmu = to_samsung_ppmu(dev_get_drvdata(dev));
+
+	return sysfs_emit(page, "0x%08x\n", samsung_ppmu->identifier);
+}
+EXPORT_SYMBOL_GPL(samsung_ppmu_identifier_attr_show);
+
+static irqreturn_t samsung_ppmu_isr(int irq, void *data)
+{
+	struct samsung_ppmu *samsung_ppmu = data;
+	unsigned long overflown;
+	int idx;
+
+	overflown = samsung_ppmu->ops->get_int_status(samsung_ppmu);
+	if (!overflown)
+		return IRQ_NONE;
+
+	/*
+	 * Find the counter index which overflowed if the bit was set
+	 * and handle it.
+	 */
+	for_each_set_bit(idx, &overflown, samsung_ppmu->num_counters)
+		samsung_ppmu->ops->clear_int_status(samsung_ppmu, idx);
+
+	return IRQ_HANDLED;
+}
+
+int samsung_ppmu_init_irq(struct samsung_ppmu *samsung_ppmu,
+			  struct platform_device *pdev)
+{
+	int irq0, irq1, ret, irq_count;
+
+	irq0 = platform_get_irq(pdev, 0);
+	if (irq0 < 0) {
+		dev_err(&pdev->dev, "Failed to get IRQ 0\n");
+		return irq0;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq0, samsung_ppmu_isr,
+			       IRQF_NOBALANCING | IRQF_NO_THREAD | IRQF_SHARED,
+			       dev_name(&pdev->dev), samsung_ppmu);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"Fail to request IRQ: %d ret: %d.\n", irq0, ret);
+		return ret;
+	}
+
+	samsung_ppmu->irq0 = irq0;
+
+	irq_count = of_property_count_elems_of_size(pdev->dev.of_node, "interrupts", sizeof(u32));
+	if (irq_count > 1) {
+		irq1 = platform_get_irq(pdev, 1);
+		if (irq1 < 0) {
+			dev_err(&pdev->dev, "Failed to get IRQ 0\n");
+			return irq1;
+		}
+
+		ret = devm_request_irq(&pdev->dev, irq1, samsung_ppmu_isr,
+				       IRQF_NOBALANCING | IRQF_NO_THREAD | IRQF_SHARED,
+				       dev_name(&pdev->dev), samsung_ppmu);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Fail to request IRQ: %d ret: %d.\n", irq1, ret);
+			return ret;
+		}
+		samsung_ppmu->irq1 = irq1;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(samsung_ppmu_init_irq);
+
+int samsung_ppmu_event_init(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct samsung_ppmu *samsung_ppmu;
+
+	if (event->attr.type != event->pmu->type)
+		return -ENOENT;
+
+	/*
+	 * We do not support sampling as the counters are all
+	 * shared by all CPU cores in a CPU die. Also we
+	 * do not support attach to a task(per-process mode)
+	 */
+	if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+		return -EOPNOTSUPP;
+
+	/* PPMU counters not specific to any CPU, so cannot support per-task */
+	if (event->cpu < 0)
+		return -EINVAL;
+
+	/* Check if events in group does not exceed the available counters */
+	samsung_ppmu = to_samsung_ppmu(event->pmu);
+	if (event->attr.config > samsung_ppmu->check_event)
+		return -EINVAL;
+
+	/*
+	 * We don't assign an index until we actually place the event onto
+	 * hardware. Use -1 to signify that we haven't decided where to put it
+	 * yet.
+	 */
+	hwc->idx = -1;
+	hwc->config_base = event->attr.config;
+
+	/* Enforce to use the same CPU for all events in this PMU */
+	event->cpu = samsung_ppmu->on_cpu;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(samsung_ppmu_event_init);
+
+/*
+ * Set the counter to count the event that we're interested in,
+ * and enable interrupt and counter.
+ */
+static void samsung_ppmu_enable_event(struct perf_event *event)
+{
+	struct samsung_ppmu *samsung_ppmu = to_samsung_ppmu(event->pmu);
+	struct hw_perf_event *hwc = &event->hw;
+
+	samsung_ppmu->ops->write_evtype(samsung_ppmu, hwc->idx,
+					SAMSUNG_PPMU_GET_EVENTID(event));
+
+	samsung_ppmu->ops->enable_counter(samsung_ppmu, hwc);
+}
+
+/*
+ * Disable counter and interrupt.
+ */
+static void samsung_ppmu_disable_event(struct perf_event *event)
+{
+	struct samsung_ppmu *samsung_ppmu = to_samsung_ppmu(event->pmu);
+	struct hw_perf_event *hwc = &event->hw;
+
+	samsung_ppmu->ops->disable_counter(samsung_ppmu, hwc);
+}
+
+void samsung_ppmu_event_update(struct perf_event *event)
+{
+	struct samsung_ppmu *samsung_ppmu = to_samsung_ppmu(event->pmu);
+	struct hw_perf_event *hwc = &event->hw;
+	u64 delta, prev_raw_count, new_raw_count;
+
+	/* read previous counter value */
+	prev_raw_count = samsung_ppmu->prev_counter[hwc->idx];
+
+	/* Read the count from the counter register */
+	new_raw_count = samsung_ppmu->ops->read_counter(samsung_ppmu, hwc);
+
+	/* compute the delta */
+	delta = new_raw_count - prev_raw_count;
+
+	local64_add(delta, &event->count);
+}
+EXPORT_SYMBOL_GPL(samsung_ppmu_event_update);
+
+void samsung_ppmu_start(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
+		return;
+
+	WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+	hwc->state = 0;
+
+	samsung_ppmu_enable_event(event);
+	perf_event_update_userpage(event);
+}
+EXPORT_SYMBOL_GPL(samsung_ppmu_start);
+
+void samsung_ppmu_stop(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	samsung_ppmu_disable_event(event);
+	WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+	hwc->state |= PERF_HES_STOPPED;
+
+	if (hwc->state & PERF_HES_UPTODATE)
+		return;
+
+	/* Read hardware counter and update the perf counter statistics */
+	samsung_ppmu_event_update(event);
+	hwc->state |= PERF_HES_UPTODATE;
+}
+EXPORT_SYMBOL_GPL(samsung_ppmu_stop);
+
+int samsung_ppmu_add(struct perf_event *event, int flags)
+{
+	struct samsung_ppmu *samsung_ppmu = to_samsung_ppmu(event->pmu);
+	struct hw_perf_event *hwc = &event->hw;
+	int idx;
+
+	hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+
+	/* Get an available counter index for counting */
+	idx = samsung_ppmu->ops->get_event_idx(event);
+	if (idx < 0)
+		return idx;
+
+	event->hw.idx = idx;
+	samsung_ppmu->pmu_events.hw_events[idx] = event;
+
+	if (flags & PERF_EF_START)
+		samsung_ppmu_start(event, PERF_EF_RELOAD);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(samsung_ppmu_add);
+
+void samsung_ppmu_del(struct perf_event *event, int flags)
+{
+	struct samsung_ppmu *samsung_ppmu = to_samsung_ppmu(event->pmu);
+	struct hw_perf_event *hwc = &event->hw;
+
+	samsung_ppmu_stop(event, PERF_EF_UPDATE);
+
+	samsung_ppmu->prev_counter[hwc->idx] = 0;
+
+	/* Clear the event bit */
+	clear_bit(hwc->idx, samsung_ppmu->pmu_events.used_mask);
+	perf_event_update_userpage(event);
+	samsung_ppmu->pmu_events.hw_events[hwc->idx] = NULL;
+}
+EXPORT_SYMBOL_GPL(samsung_ppmu_del);
+
+void samsung_ppmu_read(struct perf_event *event)
+{
+	/* Read hardware counter and update the perf counter statistics */
+	samsung_ppmu_event_update(event);
+}
+EXPORT_SYMBOL_GPL(samsung_ppmu_read);
+
+void samsung_ppmu_enable(struct pmu *pmu)
+{
+	struct samsung_ppmu *samsung_ppmu = to_samsung_ppmu(pmu);
+	bool enabled = !bitmap_empty(samsung_ppmu->pmu_events.used_mask,
+				     samsung_ppmu->num_counters);
+
+	if (!enabled)
+		return;
+
+	samsung_ppmu->ops->start_counters(samsung_ppmu);
+}
+EXPORT_SYMBOL_GPL(samsung_ppmu_enable);
+
+void samsung_ppmu_disable(struct pmu *pmu)
+{
+	struct samsung_ppmu *samsung_ppmu = to_samsung_ppmu(pmu);
+
+	samsung_ppmu->ops->stop_counters(samsung_ppmu);
+}
+EXPORT_SYMBOL_GPL(samsung_ppmu_disable);
+
+void samsung_ppmu_init(struct samsung_ppmu *s_ppmu, struct module *module)
+{
+	struct pmu *pmu = &s_ppmu->pmu;
+
+	pmu->module		= module;
+	pmu->task_ctx_nr	= perf_invalid_context;
+	pmu->event_init		= samsung_ppmu_event_init;
+	pmu->pmu_enable		= samsung_ppmu_enable;
+	pmu->pmu_disable	= samsung_ppmu_disable;
+	pmu->add		= samsung_ppmu_add;
+	pmu->del		= samsung_ppmu_del;
+	pmu->start		= samsung_ppmu_start;
+	pmu->stop		= samsung_ppmu_stop;
+	pmu->read		= samsung_ppmu_read;
+	pmu->attr_groups	= s_ppmu->pmu_events.attr_groups;
+	pmu->capabilities	= PERF_PMU_CAP_NO_EXCLUDE;
+}
+EXPORT_SYMBOL_GPL(samsung_ppmu_init);
+
+MODULE_ALIAS("perf:samsung-ppmu-core");
+MODULE_DESCRIPTION("Samsung Platform Performance Measuring Unit (PPMU) driver");
+MODULE_AUTHOR("Vivek Yadav <vivek.2311@samsung.com>");
+MODULE_AUTHOR("Ravi Patel <ravi.patel@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/perf/samsung/samsung_ppmu.h b/drivers/perf/samsung/samsung_ppmu.h
new file mode 100644
index 000000000000..2cad75cfa97b
--- /dev/null
+++ b/drivers/perf/samsung/samsung_ppmu.h
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Samsung Platform Performance Measuring Unit (PPMU) headers
+ *
+ * Copyright (c) 2024-25 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Vivek Yadav <vivek.2311@samsung.com>
+ *          Ravi Patel <ravi.patel@samsung.com>
+ */
+
+#ifndef __SAMSUNG_PPMU_H__
+#define __SAMSUNG_PPMU_H__
+
+#include <linux/clk.h>
+
+#define PPMU_MAX_COUNTERS	(5)
+
+#define to_samsung_ppmu(p)	(container_of(p, struct samsung_ppmu, pmu))
+
+#define SAMSUNG_PPMU_ATTR(_name, _func, _config)			\
+	(&((struct dev_ext_attribute[]) {				\
+		{ __ATTR(_name, 0444, _func, NULL), (void *)_config }	\
+	})[0].attr.attr)
+
+#define SAMSUNG_PPMU_FORMAT_ATTR(_name, _config)		\
+	SAMSUNG_PPMU_ATTR(_name, samsung_ppmu_format_sysfs_show, (void *)_config)
+#define SAMSUNG_PPMU_EVENT_ATTR(_name, _config)		\
+	SAMSUNG_PPMU_ATTR(_name, samsung_ppmu_event_sysfs_show, (unsigned long)_config)
+
+#define SAMSUNG_PPMU_GET_EVENTID(ev) ((ev)->hw.config_base & 0xff)
+
+enum ppmu_clock_type {
+	PPMU_ACLK,
+	PPMU_PCLK,
+	PPMU_CLK_COUNT,
+};
+
+enum ppmu_status {
+	PPMU_STOP,
+	PPMU_START,
+};
+
+struct samsung_ppmu;
+
+struct samsung_ppmu_ops {
+	void (*write_evtype)(struct samsung_ppmu *s_ppmu, int idx, u32 type);
+	int (*get_event_idx)(struct perf_event *event);
+	u64 (*read_counter)(struct samsung_ppmu *s_ppmu, struct hw_perf_event *event);
+	void (*enable_counter)(struct samsung_ppmu *s_ppmu, struct hw_perf_event *event);
+	void (*disable_counter)(struct samsung_ppmu *s_ppmu, struct hw_perf_event *event);
+	void (*start_counters)(struct samsung_ppmu *s_ppmu);
+	void (*stop_counters)(struct samsung_ppmu *s_ppmu);
+	u32 (*get_int_status)(struct samsung_ppmu *s_ppmu);
+	void (*clear_int_status)(struct samsung_ppmu *s_ppmu, int idx);
+};
+
+/* Describes the Samsung PPMU features information */
+struct samsung_ppmu_dev_info {
+	const char *name;
+	const struct attribute_group **attr_groups;
+	void *private;
+};
+
+struct samsung_ppmu_hwevents {
+	struct perf_event *hw_events[PPMU_MAX_COUNTERS];
+	DECLARE_BITMAP(used_mask, PPMU_MAX_COUNTERS);
+	const struct attribute_group **attr_groups;
+};
+
+struct samsung_ppmu_drv_data {
+	const struct attribute_group **ppmu_attr_group;
+};
+
+/* Generic pmu struct for different pmu types */
+struct samsung_ppmu {
+	struct pmu pmu;
+	const struct samsung_ppmu_ops *ops;
+	const struct samsung_ppmu_dev_info *dev_info;
+	struct samsung_ppmu_hwevents pmu_events;
+	const struct samsung_ppmu_drv_data *ppmu_data;
+	u32 samsung_ppmu_version;
+	u32 samsung_ppmu_master_id_val;
+	u8 status;
+	u8 id;
+	/* CPU used for counting */
+	int on_cpu;
+	int irq0;
+	int irq1;
+	struct device *dev;
+	struct hlist_node node;
+	void __iomem *base;
+	int num_counters;
+	u32 counter_overflow[PPMU_MAX_COUNTERS];
+	u64 prev_counter[PPMU_MAX_COUNTERS];
+	/* check event code range */
+	int check_event;
+	u32 identifier;
+	struct clk_bulk_data clks[PPMU_CLK_COUNT];
+};
+
+void samsung_ppmu_read(struct perf_event *event);
+int samsung_ppmu_add(struct perf_event *event, int flags);
+void samsung_ppmu_del(struct perf_event *event, int flags);
+void samsung_ppmu_start(struct perf_event *event, int flags);
+void samsung_ppmu_stop(struct perf_event *event, int flags);
+void samsung_ppmu_set_event_period(struct perf_event *event);
+void samsung_ppmu_event_update(struct perf_event *event);
+int samsung_ppmu_event_init(struct perf_event *event);
+void samsung_ppmu_enable(struct pmu *pmu);
+void samsung_ppmu_disable(struct pmu *pmu);
+ssize_t samsung_ppmu_event_sysfs_show(struct device *dev,
+				      struct device_attribute *attr, char *buf);
+ssize_t samsung_ppmu_format_sysfs_show(struct device *dev,
+				       struct device_attribute *attr, char *buf);
+ssize_t samsung_ppmu_cpumask_sysfs_show(struct device *dev,
+					struct device_attribute *attr, char *buf);
+int samsung_ppmu_online_cpu(unsigned int cpu, struct hlist_node *node);
+int samsung_ppmu_offline_cpu(unsigned int cpu, struct hlist_node *node);
+
+ssize_t samsung_ppmu_identifier_attr_show(struct device *dev,
+					  struct device_attribute *attr,
+					  char *page);
+int samsung_ppmu_init_irq(struct samsung_ppmu *samsung_ppmu,
+			  struct platform_device *pdev);
+
+void samsung_ppmu_init(struct samsung_ppmu *samsung_ppmu, struct module *module);
+
+#endif /* __SAMSUNG_PPMU_H__ */
-- 
2.49.0


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

* [PATCH 5/6] arm64: dts: fsd: Add PPMU support for MFC block of FSD SoC
       [not found]   ` <CGME20250708103243epcas5p2d8fd5bf02e64e104eca3def802813230@epcas5p2.samsung.com>
@ 2025-07-08 10:32     ` Vivek Yadav
  2025-07-09 14:02       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 12+ messages in thread
From: Vivek Yadav @ 2025-07-08 10:32 UTC (permalink / raw)
  To: pankaj.dubey, ravi.patel, shradha.t, mturquette, sboyd, robh,
	krzk, krzk+dt, conor+dt, will, mark.rutland, s.nawrocki,
	cw00.choi, alim.akhtar, linux-fsd
  Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-perf-users, linux-samsung-soc, Vivek Yadav

Add device tree node for PPMU instances in MFC block and
enable the same for Tesla FSD platform.

Signed-off-by: Ravi Patel <ravi.patel@samsung.com>
Signed-off-by: Vivek Yadav <vivek.2311@samsung.com>
---
 arch/arm64/boot/dts/tesla/fsd-evb.dts |  8 ++++++++
 arch/arm64/boot/dts/tesla/fsd.dtsi    | 20 ++++++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/arch/arm64/boot/dts/tesla/fsd-evb.dts b/arch/arm64/boot/dts/tesla/fsd-evb.dts
index 8d7794642900..f543c7dad7cc 100644
--- a/arch/arm64/boot/dts/tesla/fsd-evb.dts
+++ b/arch/arm64/boot/dts/tesla/fsd-evb.dts
@@ -110,3 +110,11 @@ &serial_0 {
 &ufs {
 	status = "okay";
 };
+
+&ppmu0_mfc {
+	status = "okay";
+};
+
+&ppmu1_mfc {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/tesla/fsd.dtsi b/arch/arm64/boot/dts/tesla/fsd.dtsi
index 690b4ed9c29b..7b6e7d81be10 100644
--- a/arch/arm64/boot/dts/tesla/fsd.dtsi
+++ b/arch/arm64/boot/dts/tesla/fsd.dtsi
@@ -970,6 +970,26 @@ timer@10040000 {
 			clock-names = "fin_pll", "mct";
 		};
 
+		ppmu0_mfc: ppmu@12840000 {
+			compatible = "samsung,ppmu-v2";
+			reg = <0x0 0x12840000 0x0 0x1000>;
+			interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock_mfc MFC_PPMU_MFCD0_IPCLKPORT_ACLK>,
+				 <&clock_mfc MFC_PPMU_MFCD0_IPCLKPORT_PCLK>;
+			clock-names = "aclk", "pclk";
+		};
+
+		ppmu1_mfc: ppmu@12850000 {
+			compatible = "samsung,ppmu-v2";
+			reg = <0x0 0x12850000 0x0 0x1000>;
+			interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock_mfc MFC_PPMU_MFCD1_IPCLKPORT_ACLK>,
+				 <&clock_mfc MFC_PPMU_MFCD1_IPCLKPORT_PCLK>;
+			clock-names = "aclk", "pclk";
+		};
+
 		mfc: mfc@12880000 {
 			compatible = "tesla,fsd-mfc";
 			reg = <0x0 0x12880000 0x0 0x10000>;
-- 
2.49.0


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

* [PATCH 6/6] MAINTAINERS: Add maintainers for Samsung PPMU driver
       [not found]   ` <CGME20250708103246epcas5p47b446ec342f9d49361c0a9a3929bcdd2@epcas5p4.samsung.com>
@ 2025-07-08 10:32     ` Vivek Yadav
  2025-07-09 14:06       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 12+ messages in thread
From: Vivek Yadav @ 2025-07-08 10:32 UTC (permalink / raw)
  To: pankaj.dubey, ravi.patel, shradha.t, mturquette, sboyd, robh,
	krzk, krzk+dt, conor+dt, will, mark.rutland, s.nawrocki,
	cw00.choi, alim.akhtar, linux-fsd
  Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-perf-users, linux-samsung-soc, Vivek Yadav

Add maintainers entry for Samsung PPMU driver

Signed-off-by: Ravi Patel <ravi.patel@samsung.com>
Signed-off-by: Vivek Yadav <vivek.2311@samsung.com>
---
 MAINTAINERS | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index ca11a553d412..5895b4e70c9e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21023,6 +21023,13 @@ F:	drivers/regulator/s5m*.c
 F:	drivers/rtc/rtc-s5m.c
 F:	include/linux/mfd/samsung/
 
+SAMSUNG PPMU DRIVER
+M:	Vivek Yadav <vivek.2311@samsung.com>
+M:	Ravi Patel <ravi.patel@samsung.com>
+S:	Supported
+F:	Documentation/devicetree/bindings/perf/samsung,ppmu-v2.yaml
+F:	drivers/perf/samsung/
+
 SAMSUNG S3C24XX/S3C64XX SOC SERIES CAMIF DRIVER
 M:	Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
 L:	linux-media@vger.kernel.org
-- 
2.49.0


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

* Re: [PATCH 3/6] dt-bindings: perf: Add devicetree binding for custom PPMU
  2025-07-08 10:32     ` [PATCH 3/6] dt-bindings: perf: Add devicetree binding for custom PPMU Vivek Yadav
@ 2025-07-09 14:01       ` Krzysztof Kozlowski
  0 siblings, 0 replies; 12+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-09 14:01 UTC (permalink / raw)
  To: Vivek Yadav, pankaj.dubey, ravi.patel, shradha.t, mturquette,
	sboyd, robh, krzk+dt, conor+dt, will, mark.rutland, s.nawrocki,
	cw00.choi, alim.akhtar, linux-fsd
  Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-perf-users, linux-samsung-soc

On 08/07/2025 12:32, Vivek Yadav wrote:
> Add the dt-binding documentation for the Samsung specific
> Platform Performance Monitoring Unit (PPMU) driver which provides
> performance statistics for AXI bus masters such as MFC.

A nit, subject: drop second/last, redundant "devicetree bindings". The
"dt-bindings" prefix is already stating that these are bindings.
See also:
https://elixir.bootlin.com/linux/v6.7-rc8/source/Documentation/devicetree/bindings/submitting-patches.rst#L18

> 
> Signed-off-by: Ravi Patel <ravi.patel@samsung.com>
> Signed-off-by: Vivek Yadav <vivek.2311@samsung.com>
> ---
>  .../bindings/perf/samsung,ppmu-v2.yaml        | 62 +++++++++++++++++++
>  1 file changed, 62 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/perf/samsung,ppmu-v2.yaml
> 
> diff --git a/Documentation/devicetree/bindings/perf/samsung,ppmu-v2.yaml b/Documentation/devicetree/bindings/perf/samsung,ppmu-v2.yaml
> new file mode 100644
> index 000000000000..d137d06b7034
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/perf/samsung,ppmu-v2.yaml
> @@ -0,0 +1,62 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/perf/samsung,ppmu-v2.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Samsung PPMU (Platform Performance Monitoring Unit)
> +
> +maintainers:
> +  - Vivek Yadav <vivek.2311@samsung.com>
> +  - Ravi Patel <ravi.patel@samsung.com>
> +
> +description:
> +  PPMU (Platform Performance Monitoring Unit) provides performance statistics
> +  such as bandwidth, read and write request, transactions count for AXI masters
> +  like MFC.
> +
> +properties:
> +  compatible:
> +    const: samsung,ppmu-v2

What is wrong with existing bindings? Anyway, this must be SoC specific.

> +
> +  reg:
> +    maxItems: 1
> +    description: Memory-mapped register address
> +
> +  clocks:
> +    items:
> +      - description: AXI bus clock
> +      - description: Peripheral clock
> +
> +  clock-names:
> +    items:
> +      - const: aclk
> +      - const: pclk
> +
> +  interrupts:
> +    items:
> +      - description: Overflow interrupt for Counters
> +      - description: Conditional Interrupt Generation (CIG)
> +
> +required:
> +  - compatible
> +  - reg
> +  - clocks
> +  - clock-names
> +  - interrupts
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/clock/fsd-clk.h>
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    ppmu@12840000 {

Node names should be generic. See also an explanation and list of
examples (not exhaustive) in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation


> +        compatible = "samsung,ppmu-v2";
> +        reg = <0x12840000 0x1000>;
> +        interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
> +                     <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
> +        clocks = <&clock_mfc MFC_PPMU_MFCD0_IPCLKPORT_ACLK>,
> +                 <&clock_mfc MFC_PPMU_MFCD0_IPCLKPORT_PCLK>;
> +        clock-names = "aclk", "pclk";
> +     };


Best regards,
Krzysztof

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

* Re: [PATCH 5/6] arm64: dts: fsd: Add PPMU support for MFC block of FSD SoC
  2025-07-08 10:32     ` [PATCH 5/6] arm64: dts: fsd: Add PPMU support for MFC block of FSD SoC Vivek Yadav
@ 2025-07-09 14:02       ` Krzysztof Kozlowski
  0 siblings, 0 replies; 12+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-09 14:02 UTC (permalink / raw)
  To: Vivek Yadav, pankaj.dubey, ravi.patel, shradha.t, mturquette,
	sboyd, robh, krzk+dt, conor+dt, will, mark.rutland, s.nawrocki,
	cw00.choi, alim.akhtar, linux-fsd
  Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-perf-users, linux-samsung-soc

On 08/07/2025 12:32, Vivek Yadav wrote:
> Add device tree node for PPMU instances in MFC block and
> enable the same for Tesla FSD platform.
> 
> Signed-off-by: Ravi Patel <ravi.patel@samsung.com>
> Signed-off-by: Vivek Yadav <vivek.2311@samsung.com>
> ---
>  arch/arm64/boot/dts/tesla/fsd-evb.dts |  8 ++++++++
>  arch/arm64/boot/dts/tesla/fsd.dtsi    | 20 ++++++++++++++++++++
>  2 files changed, 28 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/tesla/fsd-evb.dts b/arch/arm64/boot/dts/tesla/fsd-evb.dts
> index 8d7794642900..f543c7dad7cc 100644
> --- a/arch/arm64/boot/dts/tesla/fsd-evb.dts
> +++ b/arch/arm64/boot/dts/tesla/fsd-evb.dts
> @@ -110,3 +110,11 @@ &serial_0 {
>  &ufs {
>  	status = "okay";
>  };
> +
> +&ppmu0_mfc {

Follow DTS coding style.

> +	status = "okay";
> +};
> +
> +&ppmu1_mfc {
> +	status = "okay";
> +};
> diff --git a/arch/arm64/boot/dts/tesla/fsd.dtsi b/arch/arm64/boot/dts/tesla/fsd.dtsi
> index 690b4ed9c29b..7b6e7d81be10 100644
> --- a/arch/arm64/boot/dts/tesla/fsd.dtsi
> +++ b/arch/arm64/boot/dts/tesla/fsd.dtsi
> @@ -970,6 +970,26 @@ timer@10040000 {
>  			clock-names = "fin_pll", "mct";
>  		};
>  
> +		ppmu0_mfc: ppmu@12840000 {

Node names should be generic. See also an explanation and list of
examples (not exhaustive) in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation


> +			compatible = "samsung,ppmu-v2";

See writing bindings, DTS coding style and all other documents there
explaining why this is wrong.


Best regards,
Krzysztof

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

* Re: [PATCH 4/6] drivers: perf: samsung: Add PPMU driver support
  2025-07-08 10:32     ` [PATCH 4/6] drivers: perf: samsung: Add PPMU driver support Vivek Yadav
@ 2025-07-09 14:05       ` Krzysztof Kozlowski
  2025-07-11 14:45       ` Jonathan Cameron
  1 sibling, 0 replies; 12+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-09 14:05 UTC (permalink / raw)
  To: Vivek Yadav, pankaj.dubey, ravi.patel, shradha.t, mturquette,
	sboyd, robh, krzk+dt, conor+dt, will, mark.rutland, s.nawrocki,
	cw00.choi, alim.akhtar, linux-fsd
  Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-perf-users, linux-samsung-soc

On 08/07/2025 12:32, Vivek Yadav wrote:
> +static struct platform_driver samsung_ppmu_driver = {
> +	.probe = samsung_ppmu_probe,
> +	.remove = samsung_ppmu_remove,
> +	.driver	= {
> +		.name = "samsung-ppmu",
> +		.of_match_table	= ppmu_of_match,
> +	},
> +};
> +
> +module_platform_driver(samsung_ppmu_driver);
> +
> +MODULE_ALIAS("perf:samsung-ppmu");

No, drop. What's with these aliases from samsung... second try today.
From where do you get such code?

> +MODULE_DESCRIPTION("Samsung Platform Performance Measuring Unit (PPMU) driver");
> +MODULE_AUTHOR("Vivek Yadav <vivek.2311@samsung.com>");
> +MODULE_AUTHOR("Ravi Patel <ravi.patel@samsung.com>");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/perf/samsung/ppmu_platform.c b/drivers/perf/samsung/ppmu_platform.c
> new file mode 100644
> index 000000000000..ee11311d5a61
> --- /dev/null
> +++ b/drivers/perf/samsung/ppmu_platform.c
> @@ -0,0 +1,338 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Samsung Platform Performance Measuring Unit (PPMU) core file
> + *
> + * Copyright (c) 2024-25 Samsung Electronics Co., Ltd.
> + *
> + * Authors: Vivek Yadav <vivek.2311@samsung.com>
> + *          Ravi Patel <ravi.patel@samsung.com>
> + */
> +
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/perf_event.h>
> +#include "samsung_ppmu.h"
> +
> +/*
> + * PMU format attributes
> + */
> +ssize_t samsung_ppmu_format_sysfs_show(struct device *dev,
> +				       struct device_attribute *attr, char *buf)
> +{
> +	struct dev_ext_attribute *eattr;
> +
> +	eattr = container_of(attr, struct dev_ext_attribute, attr);
> +
> +	return sysfs_emit(buf, "%s\n", (char *)eattr->var);
> +}
> +EXPORT_SYMBOL_GPL(samsung_ppmu_format_sysfs_show);

1. Where did you document ABI?
2. This is not used. You have one module, not two. Drop all exports.

3. You need to clearly explain what is wrong with existing drivers in a
very detailed way, before you start posting another (possibly
duplicated) drivers.


Best regards,
Krzysztof

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

* Re: [PATCH 6/6] MAINTAINERS: Add maintainers for Samsung PPMU driver
  2025-07-08 10:32     ` [PATCH 6/6] MAINTAINERS: Add maintainers for Samsung PPMU driver Vivek Yadav
@ 2025-07-09 14:06       ` Krzysztof Kozlowski
  0 siblings, 0 replies; 12+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-09 14:06 UTC (permalink / raw)
  To: Vivek Yadav, pankaj.dubey, ravi.patel, shradha.t, mturquette,
	sboyd, robh, krzk+dt, conor+dt, will, mark.rutland, s.nawrocki,
	cw00.choi, alim.akhtar, linux-fsd
  Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-perf-users, linux-samsung-soc

On 08/07/2025 12:32, Vivek Yadav wrote:
> Add maintainers entry for Samsung PPMU driver
> 
> Signed-off-by: Ravi Patel <ravi.patel@samsung.com>
> Signed-off-by: Vivek Yadav <vivek.2311@samsung.com>
> ---
>  MAINTAINERS | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index ca11a553d412..5895b4e70c9e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -21023,6 +21023,13 @@ F:	drivers/regulator/s5m*.c
>  F:	drivers/rtc/rtc-s5m.c
>  F:	include/linux/mfd/samsung/
>  
> +SAMSUNG PPMU DRIVER

PPMU for what? Exynos? Then add it in the name.

> +M:	Vivek Yadav <vivek.2311@samsung.com>
> +M:	Ravi Patel <ravi.patel@samsung.com>
> +S:	Supported
> +F:	Documentation/devicetree/bindings/perf/samsung,ppmu-v2.yaml
> +F:	drivers/perf/samsung/

Also, this should be added to Samsung SoC maintainer entry as well.

Best regards,
Krzysztof

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

* Re: [PATCH 4/6] drivers: perf: samsung: Add PPMU driver support
  2025-07-08 10:32     ` [PATCH 4/6] drivers: perf: samsung: Add PPMU driver support Vivek Yadav
  2025-07-09 14:05       ` Krzysztof Kozlowski
@ 2025-07-11 14:45       ` Jonathan Cameron
  1 sibling, 0 replies; 12+ messages in thread
From: Jonathan Cameron @ 2025-07-11 14:45 UTC (permalink / raw)
  To: Vivek Yadav
  Cc: pankaj.dubey, ravi.patel, shradha.t, mturquette, sboyd, robh,
	krzk, krzk+dt, conor+dt, will, mark.rutland, s.nawrocki,
	cw00.choi, alim.akhtar, linux-fsd, linux-clk, devicetree,
	linux-kernel, linux-arm-kernel, linux-perf-users,
	linux-samsung-soc

On Tue,  8 Jul 2025 16:02:06 +0530
Vivek Yadav <vivek.2311@samsung.com> wrote:

> Add Samsung PPMU driver support in the Linux perf subsystem.
> 
> PPMU24 driver configures the PPMU24 hardware which is found
> in the Samsung SoCs like Tesla FSD.
> 
> Signed-off-by: Ravi Patel <ravi.patel@samsung.com>
> Signed-off-by: Vivek Yadav <vivek.2311@samsung.com>
Hi,

My main feedback here is that you have a layer of abstraction that is
not currently useful. So unless you plan to include another driver
that makes use of the ops structures etc, just squash the whole thing into
one much simpler c file without any of the ops stuff.

Should simplify the code a lot and generally accelerate it getting
reviewed and merged.

If it becomes useful to have that abstraction in the future, that is the
point when you should add it.

Jonathan

> diff --git a/drivers/perf/samsung/Makefile b/drivers/perf/samsung/Makefile
> new file mode 100644
> index 000000000000..c9ed1e1a986e
> --- /dev/null
> +++ b/drivers/perf/samsung/Makefile
> @@ -0,0 +1,2 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +obj-$(CONFIG_SAMSUNG_PPMU24) += ppmu_platform.o ppmu.o

Not immediately obvious why this is multiple files. (no exports needed
anyway as Krzysztof pointed out.

> diff --git a/drivers/perf/samsung/ppmu.c b/drivers/perf/samsung/ppmu.c
> new file mode 100644
> index 000000000000..cacb9cdec79f
> --- /dev/null
> +++ b/drivers/perf/samsung/ppmu.c
> @@ -0,0 +1,494 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Samsung Platform Performance Measuring Unit (PPMU) driver
> + *
> + * Copyright (c) 2024-25 Samsung Electronics Co., Ltd.
> + *
> + * Authors: Vivek Yadav <vivek.2311@samsung.com>
> + *          Ravi Patel <ravi.patel@samsung.com>
> + */
> +
> +#include <linux/idr.h>
> +#include <linux/of.h>
> +#include <linux/perf_event.h>
> +#include <linux/platform_device.h>
> +#include "samsung_ppmu.h"
> +
> +#define PPMU_CLEAR_FLAG				(GENMASK(3, 0) | BIT(31))
> +
> +#define PPMU_PMCNT3_HIGH_VAL			(3)
> +#define PPMU_PMCNT2_HIGH_VAL			(2)
> +#define PPMU_RESET_CCNT				BIT(2)
> +#define PPMU_RESET_PMCNT			BIT(1)
> +
> +#define PPMU_PMNC_OP_MODE_MASK			(GENMASK(21, 20))
> +#define PPMU_PMNC_OP_MODE_OFF			(20)
> +#define PPMU_MANUAL_MODE_VAL			(0x0)
> +#define PPMU_PMNC_GLB_CNT_EN_VAL		(BIT(0))
> +#define PPMU_PMNC_RESET_PMCNT_VAL		(BIT(1))
> +#define PPMU_PMNC_RESET_CCNT_VAL		(BIT(2))
> +
> +#define PPMU_V24_IDENTIFIER			(0x45)
> +
> +#define PPMU_CCNT_IDX				(4)
> +#define PPMU_CCNT_POS_OFF			(31)
> +#define PPMU_VERSION_CHECK			(GENMASK(19, 12))
> +
> +#define PPMU_SM_ENABLE_ALL_CNT			(0xf)
> +#define PPMU_ENABLE_CCNT			BIT(31)
> +#define PPMU_FILTER_MASK			(0x7)
> +
> +/* ID of event type */
> +enum {
> +	PPMU_EVENT_READ_CHANNEL_ACTIVE		= (0x00),
> +	PPMU_EVENT_WRITE_CHANNEL_ACTIVE		= (0x01),
> +	PPMU_EVENT_READ_REQUEST			= (0x02),
> +	PPMU_EVENT_WRITE_REQUEST		= (0x03),
> +	PPMU_EVENT_READ_DATA			= (0x04),
> +	PPMU_EVENT_WRITE_DATA			= (0x05),
> +	PPMU_EVENT_WRITE_RESPONSE		= (0x06),
> +	PPMU_EVENT_LAST_READ_DATA		= (0x07),
> +	PPMU_EVENT_LAST_WRITE_DATA		= (0x08),
> +	PPMU_EVENT_READ_REQUEST_BOLCKING	= (0x10),
> +	PPMU_EVENT_WRITE_REQUEST_BOLCKING	= (0x11),
> +	PPMU_EVENT_READ_DATA_BLOCKING		= (0x12),
> +	PPMU_EVENT_WRITE_DATA_BLOCKING		= (0x13),
> +	PPMU_EVENT_WRITE_RESPONSE_BLOCKING	= (0x14),
> +	PPMU_EVENT_READ_BURST_LENGTH		= (0x2a),
> +	PPMU_EVENT_WRITE_BURST_LENGTH		= (0x2b),
> +	PPMU_EVENT_CCNT				= (0xfe),
> +	PPMU_EVENT_MAX				= (0xff),
> +};
> +
> +/* Register offsets */
> +enum ppmu_reg {
> +	PPMU_VERSION				= (0x0000),
> +	PPMU_PMNC				= (0x0004),
> +	PPMU_CNTENS				= (0x0008),
> +	PPMU_CNTENC				= (0x000c),
> +	PPMU_INTENS				= (0x0010),
> +	PPMU_INTENC				= (0x0014),
> +	PPMU_FLAG				= (0x0018),
> +	PPMU_CIG_CFG0				= (0x001c),
> +	PPMU_CIG_CFG1				= (0x0020),
> +	PPMU_CIG_CFG2				= (0x0024),
> +	PPMU_CIG_RESULT				= (0x0028),
> +	PPMU_CNT_RESET				= (0x002c),
> +	PPMU_CNT_AUTO				= (0x0030),
> +	PPMU_PMCNT0				= (0x0034),
> +	PPMU_PMCNT1				= (0x0038),
> +	PPMU_PMCNT2				= (0x003c),
> +	PPMU_PMCNT3_LOW				= (0x0040),
> +	PPMU_PMCNT3_HIGH			= (0x0044),
> +	PPMU_CCNT				= (0x0048),
> +	PPMU_PMCNT2_HIGH			= (0x0054),
> +	PPMU_CONFIG_INFO			= (0X005c),
> +	PPMU_INTERRUPT_TEST			= (0x0060),
> +	PPMU_EVENT_EV0_TYPE			= (0x0200),
> +	PPMU_EVENT_EV1_TYPE			= (0x0204),
> +	PPMU_EVENT_EV2_TYPE			= (0x0208),
> +	PPMU_EVENT_EV3_TYPE			= (0x020c),
> +	PPMU_EVENT_SM_ID_MASK			= (0x0220),
> +	PPMU_EVENT_SM_ID_VALUE			= (0x0224),
> +	PPMU_EVENT_SM_ID_A			= (0x0228),
> +	PPMU_EVENT_SM_OTHERS_V			= (0x022c),
> +	PPMU_EVENT_SM_OTHERS_A			= (0x0230),
> +	PPMU_EVENT_SAMPLE_RD_ID_MASK		= (0x0234),
> +	PPMU_EVENT_SAMPLE_RD_ID_VALUE		= (0x0238),
> +	PPMU_EVENT_SAMPLE_WR_ID_MASK		= (0x023c),
> +	PPMU_EVENT_SAMPLE_WD_ID_VALUE		= (0x0240),
> +	PPMU_EVENT_AXI_CH_TYPE			= (0x0244),
> +	PPMU_EVENT_MO_INFO			= (0x0250),
> +	PPMU_EVENT_MO_INFO_SM_ID		= (0x0254),
> +	PPMU_EVENT_MO_INFO_SAMPLE		= (0x0258),
> +	PPMU_EVENT_IMPRECISE_ERR		= (0x0260),

Brackets () not adding anything useful.


> +static void samsung_ppmu_get_stop_counters(struct samsung_ppmu *s_ppmu)
> +{
> +	u32 val;
> +
> +	/* Stop counters */
> +	val = readl(s_ppmu->base + PPMU_PMNC);
> +	val &= (~PPMU_PMNC_GLB_CNT_EN_VAL);
> +	writel(val, s_ppmu->base + PPMU_PMNC);
> +
> +	s_ppmu->status = PPMU_STOP;
If it only takes states on and off make it a bool and give it
name to indicate directly what the two states are.

	s_ppmu->started = false;

> +}

> +static const struct samsung_ppmu_ops samsung_ppmu_plat_ops = {

If there is only one implementation in a patch set it is best
to avoid abstractions and ops tables like this.

If you have multiple implementations then submit them all at once
so we can see how this is used.  For now it complicates the
driver for no known reason.


> +	.write_evtype		= samsung_ppmu_write_evtype,
> +	.get_event_idx		= samsung_ppmu_get_event_idx,
> +	.read_counter		= samsung_ppmu_get_read_counter,
> +	.enable_counter		= samsung_ppmu_get_enable_counter,
> +	.disable_counter	= samsung_ppmu_get_disable_counter,
> +	.start_counters		= samsung_ppmu_get_start_counters,
> +	.stop_counters		= samsung_ppmu_get_stop_counters,
> +	.get_int_status		= samsung_ppmu_get_int_status,
> +	.clear_int_status	= samsung_ppmu_clear_int_status,
> +};
> +
> +static int ppmu_clock_init(struct samsung_ppmu *s_ppmu)
> +{
> +	int ret = 0;
> +	struct device *dev = s_ppmu->dev;
> +
> +	s_ppmu->clks[PPMU_ACLK].id = "aclk";
> +	s_ppmu->clks[PPMU_PCLK].id = "pclk";
> +
> +	ret = devm_clk_bulk_get(dev, PPMU_CLK_COUNT, s_ppmu->clks);
> +	if (ret) {
> +		dev_err(dev, "Failed to get clocks. Err %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = clk_bulk_prepare_enable(PPMU_CLK_COUNT, s_ppmu->clks);

> +	if (ret)
> +		dev_err(dev, "Clock enable failed. Err %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int samsung_ppmu_probe(struct platform_device *pdev)
> +{
> +	struct samsung_ppmu *s_ppmu;
> +	struct device *dev = &pdev->dev;
> +	u32 version;
> +	char *name;
> +	int ret;
> +
> +	s_ppmu = devm_kzalloc(dev, sizeof(*s_ppmu), GFP_KERNEL);
> +	if (!s_ppmu)
> +		return -ENOMEM;
> +
> +	s_ppmu->dev = &pdev->dev;
> +
> +	s_ppmu->id = idr_alloc(&my_idr, dev, 0, 2, GFP_KERNEL);

Mixing devm cleaned up stuff and things that aren't is usuall a bad
idea.  You can use devm_add_action_or_reset() to deal with allocations
and configuration that does not have it's own devm interfaces.

> +	if (s_ppmu->id < 0) {
> +		dev_err(dev, "Failed to allocate ID dynamically\n");
> +		return s_ppmu->id;
> +	}
> +
> +	/* Register base address */
> +	s_ppmu->base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(s_ppmu->base)) {
> +		dev_err(dev, "IO remap failed\n");
> +		return PTR_ERR(s_ppmu->base);
> +	}
> +
> +	/* Register IRQ */
> +	ret = samsung_ppmu_init_irq(s_ppmu, pdev);
> +	if (ret)
> +		return ret;
> +
> +	s_ppmu->check_event = PPMU_EVENT_MAX;
> +	s_ppmu->num_counters = PPMU_MAX_COUNTERS;
> +	s_ppmu->on_cpu = 0;
> +	s_ppmu->identifier = PPMU_V24_IDENTIFIER;
> +
> +	s_ppmu->ppmu_data = device_get_match_data(&pdev->dev);
> +	if (!s_ppmu->ppmu_data) {
> +		dev_err(&pdev->dev, "No matching device data found\n");
> +		return -ENODEV;
> +	}
> +
> +	/* Register PPMU driver ops */
> +	s_ppmu->pmu_events.attr_groups = s_ppmu->ppmu_data->ppmu_attr_group;
> +	s_ppmu->ops = &samsung_ppmu_plat_ops;
> +
> +	/* Set private data to platform_device structure */
> +	platform_set_drvdata(pdev, s_ppmu);
> +
> +	/* Initialize the PPMU */
> +	samsung_ppmu_init(s_ppmu, THIS_MODULE);
> +
> +	ret = ppmu_clock_init(s_ppmu);
> +	if (ret)
> +		return ret;
> +
> +	version = readl(s_ppmu->base + PPMU_VERSION);
> +	version &= PPMU_VERSION_CHECK;
> +	version >>= 12;
> +	s_ppmu->samsung_ppmu_version = version;
> +
> +	name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "ppmu_v_%x_%d", version, s_ppmu->id);
> +	if (!name)
> +		return -ENOMEM;
> +
> +	ret = perf_pmu_register(&s_ppmu->pmu, name, -1);
> +	if (ret) {
> +		clk_bulk_disable_unprepare(PPMU_CLK_COUNT, s_ppmu->clks);
> +		dev_err(dev, "Failed to register PPMU in perf. Err %d\n", ret);
> +	}
> +
> +	return ret;
> +}
> +
> +static void samsung_ppmu_remove(struct platform_device *pdev)
> +{
> +	struct samsung_ppmu *s_ppmu = platform_get_drvdata(pdev);
> +
> +	clk_bulk_disable_unprepare(PPMU_CLK_COUNT, s_ppmu->clks);

Should reverse what happens in probe.  Here you turn off clocks bfore
you remove userspace interfaces which looks unlikely to be correct.

> +
> +	perf_pmu_unregister(&s_ppmu->pmu);
> +
> +	idr_remove(&my_idr, s_ppmu->id);
> +}

> diff --git a/drivers/perf/samsung/ppmu_platform.c b/drivers/perf/samsung/ppmu_platform.c
> new file mode 100644
> index 000000000000..ee11311d5a61
> --- /dev/null
> +++ b/drivers/perf/samsung/ppmu_platform.c
> @@ -0,0 +1,338 @@

> +int samsung_ppmu_init_irq(struct samsung_ppmu *samsung_ppmu,
> +			  struct platform_device *pdev)
> +{
> +	int irq0, irq1, ret, irq_count;
> +
> +	irq0 = platform_get_irq(pdev, 0);
> +	if (irq0 < 0) {
> +		dev_err(&pdev->dev, "Failed to get IRQ 0\n");
In stuff that only happens from probe() use
		return dev_err_probe(&pdev->dev, irq0, "Failed to get IRQ 0\n");
etc

> +		return irq0;
> +	}
> +
> +	ret = devm_request_irq(&pdev->dev, irq0, samsung_ppmu_isr,
> +			       IRQF_NOBALANCING | IRQF_NO_THREAD | IRQF_SHARED,
> +			       dev_name(&pdev->dev), samsung_ppmu);
> +	if (ret) {
> +		dev_err(&pdev->dev,
> +			"Fail to request IRQ: %d ret: %d.\n", irq0, ret);
> +		return ret;
> +	}
> +
> +	samsung_ppmu->irq0 = irq0;
> +
> +	irq_count = of_property_count_elems_of_size(pdev->dev.of_node, "interrupts", sizeof(u32));
> +	if (irq_count > 1) {
> +		irq1 = platform_get_irq(pdev, 1);
> +		if (irq1 < 0) {
> +			dev_err(&pdev->dev, "Failed to get IRQ 0\n");
> +			return irq1;
> +		}
> +
> +		ret = devm_request_irq(&pdev->dev, irq1, samsung_ppmu_isr,
> +				       IRQF_NOBALANCING | IRQF_NO_THREAD | IRQF_SHARED,
> +				       dev_name(&pdev->dev), samsung_ppmu);
> +		if (ret) {
> +			dev_err(&pdev->dev,
> +				"Fail to request IRQ: %d ret: %d.\n", irq1, ret);
> +			return ret;
> +		}
> +		samsung_ppmu->irq1 = irq1;
> +	}
> +
> +	return ret;

If you know it's 0, then hard code that to make it obvious that this
is the good exit path.

	return 0;

> +}
> +EXPORT_SYMBOL_GPL(samsung_ppmu_init_irq);

> +void samsung_ppmu_disable(struct pmu *pmu)
> +{
> +	struct samsung_ppmu *samsung_ppmu = to_samsung_ppmu(pmu);
> +
> +	samsung_ppmu->ops->stop_counters(samsung_ppmu);
> +}
> +EXPORT_SYMBOL_GPL(samsung_ppmu_disable);

As noted, 1 module so no exports needed.
As in many comments in this review, if you don't have multiple
stop_counters implementations, don't have these ops wrappers.
They massively increase code complexity for no gain yet.

> +
> +void samsung_ppmu_init(struct samsung_ppmu *s_ppmu, struct module *module)
> +{
> +	struct pmu *pmu = &s_ppmu->pmu;
> +
> +	pmu->module		= module;
> +	pmu->task_ctx_nr	= perf_invalid_context;
> +	pmu->event_init		= samsung_ppmu_event_init;
> +	pmu->pmu_enable		= samsung_ppmu_enable;
> +	pmu->pmu_disable	= samsung_ppmu_disable;
> +	pmu->add		= samsung_ppmu_add;
> +	pmu->del		= samsung_ppmu_del;
> +	pmu->start		= samsung_ppmu_start;
> +	pmu->stop		= samsung_ppmu_stop;
> +	pmu->read		= samsung_ppmu_read;
> +	pmu->attr_groups	= s_ppmu->pmu_events.attr_groups;
> +	pmu->capabilities	= PERF_PMU_CAP_NO_EXCLUDE;
> +}
> +EXPORT_SYMBOL_GPL(samsung_ppmu_init);

> diff --git a/drivers/perf/samsung/samsung_ppmu.h b/drivers/perf/samsung/samsung_ppmu.h
> new file mode 100644
> index 000000000000..2cad75cfa97b
> --- /dev/null
> +++ b/drivers/perf/samsung/samsung_ppmu.h

Squashing the lot into 1 c file with no header will end up simpler I think.

> @@ -0,0 +1,128 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Samsung Platform Performance Measuring Unit (PPMU) headers
> + *
> + * Copyright (c) 2024-25 Samsung Electronics Co., Ltd.
> + *
> + * Authors: Vivek Yadav <vivek.2311@samsung.com>
> + *          Ravi Patel <ravi.patel@samsung.com>
> + */
> +
> +#ifndef __SAMSUNG_PPMU_H__
> +#define __SAMSUNG_PPMU_H__
> +
> +#include <linux/clk.h>
> +
> +#define PPMU_MAX_COUNTERS	(5)

It's a number not a macro parameter, so no need for ()

> +
> +#define to_samsung_ppmu(p)	(container_of(p, struct samsung_ppmu, pmu))
> +
> +#define SAMSUNG_PPMU_ATTR(_name, _func, _config)			\
> +	(&((struct dev_ext_attribute[]) {				\
> +		{ __ATTR(_name, 0444, _func, NULL), (void *)_config }	\
> +	})[0].attr.attr)
> +
> +#define SAMSUNG_PPMU_FORMAT_ATTR(_name, _config)		\
> +	SAMSUNG_PPMU_ATTR(_name, samsung_ppmu_format_sysfs_show, (void *)_config)
> +#define SAMSUNG_PPMU_EVENT_ATTR(_name, _config)		\
> +	SAMSUNG_PPMU_ATTR(_name, samsung_ppmu_event_sysfs_show, (unsigned long)_config)
> +
> +#define SAMSUNG_PPMU_GET_EVENTID(ev) ((ev)->hw.config_base & 0xff)
> +
> +enum ppmu_clock_type {
> +	PPMU_ACLK,
> +	PPMU_PCLK,
> +	PPMU_CLK_COUNT,

Given this is (I think) just here as a counter element and hence must always
be last, good to drop the trailing ,

> +};
> +
> +enum ppmu_status {
> +	PPMU_STOP,
> +	PPMU_START,
> +};
> +
> +struct samsung_ppmu;
> +
> +struct samsung_ppmu_ops {

As mentioned above, a ops table for one implementation looks like preparation
for generalization that may never happen.  If you don't have a second
user today, just squash the calls inline and drop this.  It is easy to
bring the abstraction back at the point where it is useful (1st patch in a series
that adds a second user of shared infrastructure)

> +	void (*write_evtype)(struct samsung_ppmu *s_ppmu, int idx, u32 type);
> +	int (*get_event_idx)(struct perf_event *event);
> +	u64 (*read_counter)(struct samsung_ppmu *s_ppmu, struct hw_perf_event *event);
> +	void (*enable_counter)(struct samsung_ppmu *s_ppmu, struct hw_perf_event *event);
> +	void (*disable_counter)(struct samsung_ppmu *s_ppmu, struct hw_perf_event *event);
> +	void (*start_counters)(struct samsung_ppmu *s_ppmu);
> +	void (*stop_counters)(struct samsung_ppmu *s_ppmu);
> +	u32 (*get_int_status)(struct samsung_ppmu *s_ppmu);
> +	void (*clear_int_status)(struct samsung_ppmu *s_ppmu, int idx);
> +};
> +
> +/* Describes the Samsung PPMU features information */
> +struct samsung_ppmu_dev_info {

Not used that I can see.  You have an instance in the structure
below but nothing ever sets it.


> +	const char *name;
> +	const struct attribute_group **attr_groups;
> +	void *private;
> +};
> +
> +struct samsung_ppmu_hwevents {
If this is never used except as encapsulation of related
fields in the main structure below then no need for the type.
Just have the structure defined inline in struct samsung_ppmu

> +	struct perf_event *hw_events[PPMU_MAX_COUNTERS];
> +	DECLARE_BITMAP(used_mask, PPMU_MAX_COUNTERS);
> +	const struct attribute_group **attr_groups;
> +};
> +
> +struct samsung_ppmu_drv_data {

Currently only one value - as such just hard code it in
the driver (all these comments only apply if you don't have another
driver to post that also uses the shared infrastructure).

> +	const struct attribute_group **ppmu_attr_group;
> +};
> +
> +/* Generic pmu struct for different pmu types */
> +struct samsung_ppmu {
> +	struct pmu pmu;
> +	const struct samsung_ppmu_ops *ops;
> +	const struct samsung_ppmu_dev_info *dev_info;
> +	struct samsung_ppmu_hwevents pmu_events;
> +	const struct samsung_ppmu_drv_data *ppmu_data;
> +	u32 samsung_ppmu_version;
> +	u32 samsung_ppmu_master_id_val;
> +	u8 status;
> +	u8 id;
> +	/* CPU used for counting */
> +	int on_cpu;
> +	int irq0;
> +	int irq1;
> +	struct device *dev;
> +	struct hlist_node node;
> +	void __iomem *base;
> +	int num_counters;
> +	u32 counter_overflow[PPMU_MAX_COUNTERS];
> +	u64 prev_counter[PPMU_MAX_COUNTERS];
> +	/* check event code range */
> +	int check_event;
> +	u32 identifier;
> +	struct clk_bulk_data clks[PPMU_CLK_COUNT];
> +};
> +
> +void samsung_ppmu_read(struct perf_event *event);
> +int samsung_ppmu_add(struct perf_event *event, int flags);
> +void samsung_ppmu_del(struct perf_event *event, int flags);
> +void samsung_ppmu_start(struct perf_event *event, int flags);
> +void samsung_ppmu_stop(struct perf_event *event, int flags);
> +void samsung_ppmu_set_event_period(struct perf_event *event);
> +void samsung_ppmu_event_update(struct perf_event *event);
> +int samsung_ppmu_event_init(struct perf_event *event);
> +void samsung_ppmu_enable(struct pmu *pmu);
> +void samsung_ppmu_disable(struct pmu *pmu);
> +ssize_t samsung_ppmu_event_sysfs_show(struct device *dev,
> +				      struct device_attribute *attr, char *buf);
> +ssize_t samsung_ppmu_format_sysfs_show(struct device *dev,
> +				       struct device_attribute *attr, char *buf);
> +ssize_t samsung_ppmu_cpumask_sysfs_show(struct device *dev,
> +					struct device_attribute *attr, char *buf);
> +int samsung_ppmu_online_cpu(unsigned int cpu, struct hlist_node *node);
> +int samsung_ppmu_offline_cpu(unsigned int cpu, struct hlist_node *node);
> +
> +ssize_t samsung_ppmu_identifier_attr_show(struct device *dev,
> +					  struct device_attribute *attr,
> +					  char *page);
> +int samsung_ppmu_init_irq(struct samsung_ppmu *samsung_ppmu,
> +			  struct platform_device *pdev);
> +
> +void samsung_ppmu_init(struct samsung_ppmu *samsung_ppmu, struct module *module);
> +
> +#endif /* __SAMSUNG_PPMU_H__ */


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

end of thread, other threads:[~2025-07-11 14:45 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <CGME20250708103228epcas5p27886821d1ff225f2e5cdd4d948d03a66@epcas5p2.samsung.com>
2025-07-08 10:32 ` [PATCH 0/6] Add PPMU support for Tesla FSD Vivek Yadav
     [not found]   ` <CGME20250708103231epcas5p1b9fe52dd6ea3cdd65a5df163ba05e139@epcas5p1.samsung.com>
2025-07-08 10:32     ` [PATCH 1/6] dt-bindings: clock: Add PPMU clock definitions for FSD platform Vivek Yadav
     [not found]   ` <CGME20250708103234epcas5p1a92b0b57315f6e81c906fedcc232c279@epcas5p1.samsung.com>
2025-07-08 10:32     ` [PATCH 2/6] clk: samsung: fsd: Use clock IDs for PPMU MFC block Vivek Yadav
     [not found]   ` <CGME20250708103237epcas5p1c4c5d7a5f43c0c88317e74d2f2458a1b@epcas5p1.samsung.com>
2025-07-08 10:32     ` [PATCH 3/6] dt-bindings: perf: Add devicetree binding for custom PPMU Vivek Yadav
2025-07-09 14:01       ` Krzysztof Kozlowski
     [not found]   ` <CGME20250708103240epcas5p336539d4c3a1fb489708c61f9aae6bfa8@epcas5p3.samsung.com>
2025-07-08 10:32     ` [PATCH 4/6] drivers: perf: samsung: Add PPMU driver support Vivek Yadav
2025-07-09 14:05       ` Krzysztof Kozlowski
2025-07-11 14:45       ` Jonathan Cameron
     [not found]   ` <CGME20250708103243epcas5p2d8fd5bf02e64e104eca3def802813230@epcas5p2.samsung.com>
2025-07-08 10:32     ` [PATCH 5/6] arm64: dts: fsd: Add PPMU support for MFC block of FSD SoC Vivek Yadav
2025-07-09 14:02       ` Krzysztof Kozlowski
     [not found]   ` <CGME20250708103246epcas5p47b446ec342f9d49361c0a9a3929bcdd2@epcas5p4.samsung.com>
2025-07-08 10:32     ` [PATCH 6/6] MAINTAINERS: Add maintainers for Samsung PPMU driver Vivek Yadav
2025-07-09 14:06       ` Krzysztof Kozlowski

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).