]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
soc: samsung: exynos-pmu: move some gs101 related code into new file
authorAndré Draszik <andre.draszik@linaro.org>
Thu, 9 Oct 2025 09:31:26 +0000 (10:31 +0100)
committerKrzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Sat, 18 Oct 2025 17:16:44 +0000 (19:16 +0200)
To avoid cluttering common code, move most of the gs101 code into a new
file, gs101-pmu.c

More code is going to be added for gs101 - having it all in one file
helps keeping the common code (file) more readable. While at it, rename
variables 'ctx' to 'context' for consistency.

No functional change.

Reviewed-by: Sam Protsenko <semen.protsenko@linaro.org>
Signed-off-by: André Draszik <andre.draszik@linaro.org>
Link: https://patch.msgid.link/20251009-gs101-pmu-regmap-tables-v2-2-2d64f5261952@linaro.org
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
MAINTAINERS
drivers/soc/samsung/Makefile
drivers/soc/samsung/exynos-pmu.c
drivers/soc/samsung/exynos-pmu.h
drivers/soc/samsung/gs101-pmu.c [new file with mode: 0644]

index 46126ce2f968e4f9260263f1574ee29f5ff0de1c..88bd72b2761c51b99f06b4b10b7e8a1e36cc2061 100644 (file)
@@ -10600,6 +10600,7 @@ F:      Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
 F:     Documentation/devicetree/bindings/soc/google/google,gs101-pmu-intr-gen.yaml
 F:     arch/arm64/boot/dts/exynos/google/
 F:     drivers/clk/samsung/clk-gs101.c
+F:     drivers/soc/samsung/gs101-pmu.c
 F:     drivers/phy/samsung/phy-gs101-ufs.c
 F:     include/dt-bindings/clock/google,gs101.h
 K:     [gG]oogle.?[tT]ensor
index 248a33d7754af1a1e5fbbbb79413eb300bbbc8e5..636a762608c9ba2c22a72d6f9597ceb015f7f36c 100644 (file)
@@ -6,7 +6,8 @@ exynos_chipid-y                 += exynos-chipid.o exynos-asv.o
 
 obj-$(CONFIG_EXYNOS_USI)       += exynos-usi.o
 
-obj-$(CONFIG_EXYNOS_PMU)       += exynos-pmu.o
+obj-$(CONFIG_EXYNOS_PMU)       += exynos_pmu.o
+exynos_pmu-y                   += exynos-pmu.o gs101-pmu.o
 
 obj-$(CONFIG_EXYNOS_PMU_ARM_DRIVERS)   += exynos3250-pmu.o exynos4-pmu.o \
                                        exynos5250-pmu.o exynos5420-pmu.o
index 565eb75b003aaa715107b407f40194e0f81a18a6..f258a4ec2a3358d398fb1ea805da5fd8f2f69435 100644 (file)
@@ -6,7 +6,6 @@
 // Exynos - CPU PMU(Power Management Unit) support
 
 #include <linux/array_size.h>
-#include <linux/arm-smccc.h>
 #include <linux/bitmap.h>
 #include <linux/cpuhotplug.h>
 #include <linux/cpu_pm.h>
 
 #include "exynos-pmu.h"
 
-#define PMUALIVE_MASK                  GENMASK(13, 0)
-#define TENSOR_SET_BITS                        (BIT(15) | BIT(14))
-#define TENSOR_CLR_BITS                        BIT(15)
-#define TENSOR_SMC_PMU_SEC_REG         0x82000504
-#define TENSOR_PMUREG_READ             0
-#define TENSOR_PMUREG_WRITE            1
-#define TENSOR_PMUREG_RMW              2
-
 struct exynos_pmu_context {
        struct device *dev;
        const struct exynos_pmu_data *pmu_data;
@@ -54,125 +45,6 @@ static struct exynos_pmu_context *pmu_context;
 /* forward declaration */
 static struct platform_driver exynos_pmu_driver;
 
-/*
- * Tensor SoCs are configured so that PMU_ALIVE registers can only be written
- * from EL3, but are still read accessible. As Linux needs to write some of
- * these registers, the following functions are provided and exposed via
- * regmap.
- *
- * Note: This SMC interface is known to be implemented on gs101 and derivative
- * SoCs.
- */
-
-/* Write to a protected PMU register. */
-static int tensor_sec_reg_write(void *context, unsigned int reg,
-                               unsigned int val)
-{
-       struct arm_smccc_res res;
-       unsigned long pmu_base = (unsigned long)context;
-
-       arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg,
-                     TENSOR_PMUREG_WRITE, val, 0, 0, 0, 0, &res);
-
-       /* returns -EINVAL if access isn't allowed or 0 */
-       if (res.a0)
-               pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0);
-
-       return (int)res.a0;
-}
-
-/* Read/Modify/Write a protected PMU register. */
-static int tensor_sec_reg_rmw(void *context, unsigned int reg,
-                             unsigned int mask, unsigned int val)
-{
-       struct arm_smccc_res res;
-       unsigned long pmu_base = (unsigned long)context;
-
-       arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg,
-                     TENSOR_PMUREG_RMW, mask, val, 0, 0, 0, &res);
-
-       /* returns -EINVAL if access isn't allowed or 0 */
-       if (res.a0)
-               pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0);
-
-       return (int)res.a0;
-}
-
-/*
- * Read a protected PMU register. All PMU registers can be read by Linux.
- * Note: The SMC read register is not used, as only registers that can be
- * written are readable via SMC.
- */
-static int tensor_sec_reg_read(void *context, unsigned int reg,
-                              unsigned int *val)
-{
-       *val = pmu_raw_readl(reg);
-       return 0;
-}
-
-/*
- * For SoCs that have set/clear bit hardware this function can be used when
- * the PMU register will be accessed by multiple masters.
- *
- * For example, to set bits 13:8 in PMU reg offset 0x3e80
- * tensor_set_bits_atomic(ctx, 0x3e80, 0x3f00, 0x3f00);
- *
- * Set bit 8, and clear bits 13:9 PMU reg offset 0x3e80
- * tensor_set_bits_atomic(0x3e80, 0x100, 0x3f00);
- */
-static int tensor_set_bits_atomic(void *ctx, unsigned int offset, u32 val,
-                                 u32 mask)
-{
-       int ret;
-       unsigned int i;
-
-       for (i = 0; i < 32; i++) {
-               if (!(mask & BIT(i)))
-                       continue;
-
-               offset &= ~TENSOR_SET_BITS;
-
-               if (val & BIT(i))
-                       offset |= TENSOR_SET_BITS;
-               else
-                       offset |= TENSOR_CLR_BITS;
-
-               ret = tensor_sec_reg_write(ctx, offset, i);
-               if (ret)
-                       return ret;
-       }
-       return 0;
-}
-
-static bool tensor_is_atomic(unsigned int reg)
-{
-       /*
-        * Use atomic operations for PMU_ALIVE registers (offset 0~0x3FFF)
-        * as the target registers can be accessed by multiple masters. SFRs
-        * that don't support atomic are added to the switch statement below.
-        */
-       if (reg > PMUALIVE_MASK)
-               return false;
-
-       switch (reg) {
-       case GS101_SYSIP_DAT0:
-       case GS101_SYSTEM_CONFIGURATION:
-               return false;
-       default:
-               return true;
-       }
-}
-
-static int tensor_sec_update_bits(void *ctx, unsigned int reg,
-                                 unsigned int mask, unsigned int val)
-{
-
-       if (!tensor_is_atomic(reg))
-               return tensor_sec_reg_rmw(ctx, reg, mask, val);
-
-       return tensor_set_bits_atomic(ctx, reg, val, mask);
-}
-
 void pmu_raw_writel(u32 val, u32 offset)
 {
        writel_relaxed(val, pmu_base_addr + offset);
@@ -244,11 +116,6 @@ static const struct regmap_config regmap_pmu_intr = {
        .use_raw_spinlock = true,
 };
 
-static const struct exynos_pmu_data gs101_pmu_data = {
-       .pmu_secure = true,
-       .pmu_cpuhp = true,
-};
-
 /*
  * PMU platform driver and devicetree bindings.
  */
index 1658a55fe61c6fe70cc4cb0fcdcea2756096a268..fbe381e2a2e1062c318b10b3df171e328901fa7a 100644 (file)
@@ -70,7 +70,14 @@ extern const struct exynos_pmu_data exynos4412_pmu_data;
 extern const struct exynos_pmu_data exynos5250_pmu_data;
 extern const struct exynos_pmu_data exynos5420_pmu_data;
 #endif
+extern const struct exynos_pmu_data gs101_pmu_data;
 
 extern void pmu_raw_writel(u32 val, u32 offset);
 extern u32 pmu_raw_readl(u32 offset);
+
+int tensor_sec_reg_write(void *context, unsigned int reg, unsigned int val);
+int tensor_sec_reg_read(void *context, unsigned int reg, unsigned int *val);
+int tensor_sec_update_bits(void *context, unsigned int reg, unsigned int mask,
+                          unsigned int val);
+
 #endif /* __EXYNOS_PMU_H */
diff --git a/drivers/soc/samsung/gs101-pmu.c b/drivers/soc/samsung/gs101-pmu.c
new file mode 100644 (file)
index 0000000..ec345d0
--- /dev/null
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2025 Linaro Ltd.
+ *
+ * GS101 PMU (Power Management Unit) support
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/array_size.h>
+#include <linux/soc/samsung/exynos-pmu.h>
+#include <linux/soc/samsung/exynos-regs-pmu.h>
+
+#include "exynos-pmu.h"
+
+#define PMUALIVE_MASK                  GENMASK(13, 0)
+#define TENSOR_SET_BITS                        (BIT(15) | BIT(14))
+#define TENSOR_CLR_BITS                        BIT(15)
+#define TENSOR_SMC_PMU_SEC_REG         0x82000504
+#define TENSOR_PMUREG_READ             0
+#define TENSOR_PMUREG_WRITE            1
+#define TENSOR_PMUREG_RMW              2
+
+const struct exynos_pmu_data gs101_pmu_data = {
+       .pmu_secure = true,
+       .pmu_cpuhp = true,
+};
+
+/*
+ * Tensor SoCs are configured so that PMU_ALIVE registers can only be written
+ * from EL3, but are still read accessible. As Linux needs to write some of
+ * these registers, the following functions are provided and exposed via
+ * regmap.
+ *
+ * Note: This SMC interface is known to be implemented on gs101 and derivative
+ * SoCs.
+ */
+
+/* Write to a protected PMU register. */
+int tensor_sec_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+       struct arm_smccc_res res;
+       unsigned long pmu_base = (unsigned long)context;
+
+       arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg,
+                     TENSOR_PMUREG_WRITE, val, 0, 0, 0, 0, &res);
+
+       /* returns -EINVAL if access isn't allowed or 0 */
+       if (res.a0)
+               pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0);
+
+       return (int)res.a0;
+}
+
+/* Read/Modify/Write a protected PMU register. */
+static int tensor_sec_reg_rmw(void *context, unsigned int reg,
+                             unsigned int mask, unsigned int val)
+{
+       struct arm_smccc_res res;
+       unsigned long pmu_base = (unsigned long)context;
+
+       arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg,
+                     TENSOR_PMUREG_RMW, mask, val, 0, 0, 0, &res);
+
+       /* returns -EINVAL if access isn't allowed or 0 */
+       if (res.a0)
+               pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0);
+
+       return (int)res.a0;
+}
+
+/*
+ * Read a protected PMU register. All PMU registers can be read by Linux.
+ * Note: The SMC read register is not used, as only registers that can be
+ * written are readable via SMC.
+ */
+int tensor_sec_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+       *val = pmu_raw_readl(reg);
+       return 0;
+}
+
+/*
+ * For SoCs that have set/clear bit hardware this function can be used when
+ * the PMU register will be accessed by multiple masters.
+ *
+ * For example, to set bits 13:8 in PMU reg offset 0x3e80
+ * tensor_set_bits_atomic(ctx, 0x3e80, 0x3f00, 0x3f00);
+ *
+ * Set bit 8, and clear bits 13:9 PMU reg offset 0x3e80
+ * tensor_set_bits_atomic(0x3e80, 0x100, 0x3f00);
+ */
+static int tensor_set_bits_atomic(void *context, unsigned int offset, u32 val,
+                                 u32 mask)
+{
+       int ret;
+       unsigned int i;
+
+       for (i = 0; i < 32; i++) {
+               if (!(mask & BIT(i)))
+                       continue;
+
+               offset &= ~TENSOR_SET_BITS;
+
+               if (val & BIT(i))
+                       offset |= TENSOR_SET_BITS;
+               else
+                       offset |= TENSOR_CLR_BITS;
+
+               ret = tensor_sec_reg_write(context, offset, i);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+static bool tensor_is_atomic(unsigned int reg)
+{
+       /*
+        * Use atomic operations for PMU_ALIVE registers (offset 0~0x3FFF)
+        * as the target registers can be accessed by multiple masters. SFRs
+        * that don't support atomic are added to the switch statement below.
+        */
+       if (reg > PMUALIVE_MASK)
+               return false;
+
+       switch (reg) {
+       case GS101_SYSIP_DAT0:
+       case GS101_SYSTEM_CONFIGURATION:
+               return false;
+       default:
+               return true;
+       }
+}
+
+int tensor_sec_update_bits(void *context, unsigned int reg, unsigned int mask,
+                          unsigned int val)
+{
+       if (!tensor_is_atomic(reg))
+               return tensor_sec_reg_rmw(context, reg, mask, val);
+
+       return tensor_set_bits_atomic(context, reg, val, mask);
+}