Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

soc: samsung: exynos-pmu: move some gs101 related code into new file

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>

authored by

André Draszik and committed by
Krzysztof Kozlowski
b320711e 1fce7e4d

+152 -134
+1
MAINTAINERS
··· 10600 10600 F: Documentation/devicetree/bindings/soc/google/google,gs101-pmu-intr-gen.yaml 10601 10601 F: arch/arm64/boot/dts/exynos/google/ 10602 10602 F: drivers/clk/samsung/clk-gs101.c 10603 + F: drivers/soc/samsung/gs101-pmu.c 10603 10604 F: drivers/phy/samsung/phy-gs101-ufs.c 10604 10605 F: include/dt-bindings/clock/google,gs101.h 10605 10606 K: [gG]oogle.?[tT]ensor
+2 -1
drivers/soc/samsung/Makefile
··· 6 6 7 7 obj-$(CONFIG_EXYNOS_USI) += exynos-usi.o 8 8 9 - obj-$(CONFIG_EXYNOS_PMU) += exynos-pmu.o 9 + obj-$(CONFIG_EXYNOS_PMU) += exynos_pmu.o 10 + exynos_pmu-y += exynos-pmu.o gs101-pmu.o 10 11 11 12 obj-$(CONFIG_EXYNOS_PMU_ARM_DRIVERS) += exynos3250-pmu.o exynos4-pmu.o \ 12 13 exynos5250-pmu.o exynos5420-pmu.o
-133
drivers/soc/samsung/exynos-pmu.c
··· 6 6 // Exynos - CPU PMU(Power Management Unit) support 7 7 8 8 #include <linux/array_size.h> 9 - #include <linux/arm-smccc.h> 10 9 #include <linux/bitmap.h> 11 10 #include <linux/cpuhotplug.h> 12 11 #include <linux/cpu_pm.h> ··· 23 24 #include <linux/soc/samsung/exynos-pmu.h> 24 25 25 26 #include "exynos-pmu.h" 26 - 27 - #define PMUALIVE_MASK GENMASK(13, 0) 28 - #define TENSOR_SET_BITS (BIT(15) | BIT(14)) 29 - #define TENSOR_CLR_BITS BIT(15) 30 - #define TENSOR_SMC_PMU_SEC_REG 0x82000504 31 - #define TENSOR_PMUREG_READ 0 32 - #define TENSOR_PMUREG_WRITE 1 33 - #define TENSOR_PMUREG_RMW 2 34 27 35 28 struct exynos_pmu_context { 36 29 struct device *dev; ··· 44 53 static struct exynos_pmu_context *pmu_context; 45 54 /* forward declaration */ 46 55 static struct platform_driver exynos_pmu_driver; 47 - 48 - /* 49 - * Tensor SoCs are configured so that PMU_ALIVE registers can only be written 50 - * from EL3, but are still read accessible. As Linux needs to write some of 51 - * these registers, the following functions are provided and exposed via 52 - * regmap. 53 - * 54 - * Note: This SMC interface is known to be implemented on gs101 and derivative 55 - * SoCs. 56 - */ 57 - 58 - /* Write to a protected PMU register. */ 59 - static int tensor_sec_reg_write(void *context, unsigned int reg, 60 - unsigned int val) 61 - { 62 - struct arm_smccc_res res; 63 - unsigned long pmu_base = (unsigned long)context; 64 - 65 - arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg, 66 - TENSOR_PMUREG_WRITE, val, 0, 0, 0, 0, &res); 67 - 68 - /* returns -EINVAL if access isn't allowed or 0 */ 69 - if (res.a0) 70 - pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0); 71 - 72 - return (int)res.a0; 73 - } 74 - 75 - /* Read/Modify/Write a protected PMU register. */ 76 - static int tensor_sec_reg_rmw(void *context, unsigned int reg, 77 - unsigned int mask, unsigned int val) 78 - { 79 - struct arm_smccc_res res; 80 - unsigned long pmu_base = (unsigned long)context; 81 - 82 - arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg, 83 - TENSOR_PMUREG_RMW, mask, val, 0, 0, 0, &res); 84 - 85 - /* returns -EINVAL if access isn't allowed or 0 */ 86 - if (res.a0) 87 - pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0); 88 - 89 - return (int)res.a0; 90 - } 91 - 92 - /* 93 - * Read a protected PMU register. All PMU registers can be read by Linux. 94 - * Note: The SMC read register is not used, as only registers that can be 95 - * written are readable via SMC. 96 - */ 97 - static int tensor_sec_reg_read(void *context, unsigned int reg, 98 - unsigned int *val) 99 - { 100 - *val = pmu_raw_readl(reg); 101 - return 0; 102 - } 103 - 104 - /* 105 - * For SoCs that have set/clear bit hardware this function can be used when 106 - * the PMU register will be accessed by multiple masters. 107 - * 108 - * For example, to set bits 13:8 in PMU reg offset 0x3e80 109 - * tensor_set_bits_atomic(ctx, 0x3e80, 0x3f00, 0x3f00); 110 - * 111 - * Set bit 8, and clear bits 13:9 PMU reg offset 0x3e80 112 - * tensor_set_bits_atomic(0x3e80, 0x100, 0x3f00); 113 - */ 114 - static int tensor_set_bits_atomic(void *ctx, unsigned int offset, u32 val, 115 - u32 mask) 116 - { 117 - int ret; 118 - unsigned int i; 119 - 120 - for (i = 0; i < 32; i++) { 121 - if (!(mask & BIT(i))) 122 - continue; 123 - 124 - offset &= ~TENSOR_SET_BITS; 125 - 126 - if (val & BIT(i)) 127 - offset |= TENSOR_SET_BITS; 128 - else 129 - offset |= TENSOR_CLR_BITS; 130 - 131 - ret = tensor_sec_reg_write(ctx, offset, i); 132 - if (ret) 133 - return ret; 134 - } 135 - return 0; 136 - } 137 - 138 - static bool tensor_is_atomic(unsigned int reg) 139 - { 140 - /* 141 - * Use atomic operations for PMU_ALIVE registers (offset 0~0x3FFF) 142 - * as the target registers can be accessed by multiple masters. SFRs 143 - * that don't support atomic are added to the switch statement below. 144 - */ 145 - if (reg > PMUALIVE_MASK) 146 - return false; 147 - 148 - switch (reg) { 149 - case GS101_SYSIP_DAT0: 150 - case GS101_SYSTEM_CONFIGURATION: 151 - return false; 152 - default: 153 - return true; 154 - } 155 - } 156 - 157 - static int tensor_sec_update_bits(void *ctx, unsigned int reg, 158 - unsigned int mask, unsigned int val) 159 - { 160 - 161 - if (!tensor_is_atomic(reg)) 162 - return tensor_sec_reg_rmw(ctx, reg, mask, val); 163 - 164 - return tensor_set_bits_atomic(ctx, reg, val, mask); 165 - } 166 56 167 57 void pmu_raw_writel(u32 val, u32 offset) 168 58 { ··· 114 242 .reg_stride = 4, 115 243 .val_bits = 32, 116 244 .use_raw_spinlock = true, 117 - }; 118 - 119 - static const struct exynos_pmu_data gs101_pmu_data = { 120 - .pmu_secure = true, 121 - .pmu_cpuhp = true, 122 245 }; 123 246 124 247 /*
+7
drivers/soc/samsung/exynos-pmu.h
··· 70 70 extern const struct exynos_pmu_data exynos5250_pmu_data; 71 71 extern const struct exynos_pmu_data exynos5420_pmu_data; 72 72 #endif 73 + extern const struct exynos_pmu_data gs101_pmu_data; 73 74 74 75 extern void pmu_raw_writel(u32 val, u32 offset); 75 76 extern u32 pmu_raw_readl(u32 offset); 77 + 78 + int tensor_sec_reg_write(void *context, unsigned int reg, unsigned int val); 79 + int tensor_sec_reg_read(void *context, unsigned int reg, unsigned int *val); 80 + int tensor_sec_update_bits(void *context, unsigned int reg, unsigned int mask, 81 + unsigned int val); 82 + 76 83 #endif /* __EXYNOS_PMU_H */
+142
drivers/soc/samsung/gs101-pmu.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright 2025 Linaro Ltd. 4 + * 5 + * GS101 PMU (Power Management Unit) support 6 + */ 7 + 8 + #include <linux/arm-smccc.h> 9 + #include <linux/array_size.h> 10 + #include <linux/soc/samsung/exynos-pmu.h> 11 + #include <linux/soc/samsung/exynos-regs-pmu.h> 12 + 13 + #include "exynos-pmu.h" 14 + 15 + #define PMUALIVE_MASK GENMASK(13, 0) 16 + #define TENSOR_SET_BITS (BIT(15) | BIT(14)) 17 + #define TENSOR_CLR_BITS BIT(15) 18 + #define TENSOR_SMC_PMU_SEC_REG 0x82000504 19 + #define TENSOR_PMUREG_READ 0 20 + #define TENSOR_PMUREG_WRITE 1 21 + #define TENSOR_PMUREG_RMW 2 22 + 23 + const struct exynos_pmu_data gs101_pmu_data = { 24 + .pmu_secure = true, 25 + .pmu_cpuhp = true, 26 + }; 27 + 28 + /* 29 + * Tensor SoCs are configured so that PMU_ALIVE registers can only be written 30 + * from EL3, but are still read accessible. As Linux needs to write some of 31 + * these registers, the following functions are provided and exposed via 32 + * regmap. 33 + * 34 + * Note: This SMC interface is known to be implemented on gs101 and derivative 35 + * SoCs. 36 + */ 37 + 38 + /* Write to a protected PMU register. */ 39 + int tensor_sec_reg_write(void *context, unsigned int reg, unsigned int val) 40 + { 41 + struct arm_smccc_res res; 42 + unsigned long pmu_base = (unsigned long)context; 43 + 44 + arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg, 45 + TENSOR_PMUREG_WRITE, val, 0, 0, 0, 0, &res); 46 + 47 + /* returns -EINVAL if access isn't allowed or 0 */ 48 + if (res.a0) 49 + pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0); 50 + 51 + return (int)res.a0; 52 + } 53 + 54 + /* Read/Modify/Write a protected PMU register. */ 55 + static int tensor_sec_reg_rmw(void *context, unsigned int reg, 56 + unsigned int mask, unsigned int val) 57 + { 58 + struct arm_smccc_res res; 59 + unsigned long pmu_base = (unsigned long)context; 60 + 61 + arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg, 62 + TENSOR_PMUREG_RMW, mask, val, 0, 0, 0, &res); 63 + 64 + /* returns -EINVAL if access isn't allowed or 0 */ 65 + if (res.a0) 66 + pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0); 67 + 68 + return (int)res.a0; 69 + } 70 + 71 + /* 72 + * Read a protected PMU register. All PMU registers can be read by Linux. 73 + * Note: The SMC read register is not used, as only registers that can be 74 + * written are readable via SMC. 75 + */ 76 + int tensor_sec_reg_read(void *context, unsigned int reg, unsigned int *val) 77 + { 78 + *val = pmu_raw_readl(reg); 79 + return 0; 80 + } 81 + 82 + /* 83 + * For SoCs that have set/clear bit hardware this function can be used when 84 + * the PMU register will be accessed by multiple masters. 85 + * 86 + * For example, to set bits 13:8 in PMU reg offset 0x3e80 87 + * tensor_set_bits_atomic(ctx, 0x3e80, 0x3f00, 0x3f00); 88 + * 89 + * Set bit 8, and clear bits 13:9 PMU reg offset 0x3e80 90 + * tensor_set_bits_atomic(0x3e80, 0x100, 0x3f00); 91 + */ 92 + static int tensor_set_bits_atomic(void *context, unsigned int offset, u32 val, 93 + u32 mask) 94 + { 95 + int ret; 96 + unsigned int i; 97 + 98 + for (i = 0; i < 32; i++) { 99 + if (!(mask & BIT(i))) 100 + continue; 101 + 102 + offset &= ~TENSOR_SET_BITS; 103 + 104 + if (val & BIT(i)) 105 + offset |= TENSOR_SET_BITS; 106 + else 107 + offset |= TENSOR_CLR_BITS; 108 + 109 + ret = tensor_sec_reg_write(context, offset, i); 110 + if (ret) 111 + return ret; 112 + } 113 + return 0; 114 + } 115 + 116 + static bool tensor_is_atomic(unsigned int reg) 117 + { 118 + /* 119 + * Use atomic operations for PMU_ALIVE registers (offset 0~0x3FFF) 120 + * as the target registers can be accessed by multiple masters. SFRs 121 + * that don't support atomic are added to the switch statement below. 122 + */ 123 + if (reg > PMUALIVE_MASK) 124 + return false; 125 + 126 + switch (reg) { 127 + case GS101_SYSIP_DAT0: 128 + case GS101_SYSTEM_CONFIGURATION: 129 + return false; 130 + default: 131 + return true; 132 + } 133 + } 134 + 135 + int tensor_sec_update_bits(void *context, unsigned int reg, unsigned int mask, 136 + unsigned int val) 137 + { 138 + if (!tensor_is_atomic(reg)) 139 + return tensor_sec_reg_rmw(context, reg, mask, val); 140 + 141 + return tensor_set_bits_atomic(context, reg, val, mask); 142 + }