5
5
//
6
6
// Exynos - CPU PMU(Power Management Unit) support
7
7
8
+ #include <linux/arm-smccc.h>
8
9
#include <linux/of.h>
9
10
#include <linux/of_address.h>
10
11
#include <linux/mfd/core.h>
11
12
#include <linux/mfd/syscon.h>
12
13
#include <linux/of_platform.h>
13
14
#include <linux/platform_device.h>
14
15
#include <linux/delay.h>
16
+ #include <linux/regmap.h>
15
17
16
18
#include <linux/soc/samsung/exynos-regs-pmu.h>
17
19
#include <linux/soc/samsung/exynos-pmu.h>
18
20
19
21
#include "exynos-pmu.h"
20
22
23
+ #define PMUALIVE_MASK GENMASK(13, 0)
24
+ #define TENSOR_SET_BITS (BIT(15) | BIT(14))
25
+ #define TENSOR_CLR_BITS BIT(15)
26
+ #define TENSOR_SMC_PMU_SEC_REG 0x82000504
27
+ #define TENSOR_PMUREG_READ 0
28
+ #define TENSOR_PMUREG_WRITE 1
29
+ #define TENSOR_PMUREG_RMW 2
30
+
21
31
struct exynos_pmu_context {
22
32
struct device * dev ;
23
33
const struct exynos_pmu_data * pmu_data ;
34
+ struct regmap * pmureg ;
24
35
};
25
36
26
37
void __iomem * pmu_base_addr ;
27
38
static struct exynos_pmu_context * pmu_context ;
39
+ /* forward declaration */
40
+ static struct platform_driver exynos_pmu_driver ;
41
+
42
+ /*
43
+ * Tensor SoCs are configured so that PMU_ALIVE registers can only be written
44
+ * from EL3, but are still read accessible. As Linux needs to write some of
45
+ * these registers, the following functions are provided and exposed via
46
+ * regmap.
47
+ *
48
+ * Note: This SMC interface is known to be implemented on gs101 and derivative
49
+ * SoCs.
50
+ */
51
+
52
+ /* Write to a protected PMU register. */
53
+ static int tensor_sec_reg_write (void * context , unsigned int reg ,
54
+ unsigned int val )
55
+ {
56
+ struct arm_smccc_res res ;
57
+ unsigned long pmu_base = (unsigned long )context ;
58
+
59
+ arm_smccc_smc (TENSOR_SMC_PMU_SEC_REG , pmu_base + reg ,
60
+ TENSOR_PMUREG_WRITE , val , 0 , 0 , 0 , 0 , & res );
61
+
62
+ /* returns -EINVAL if access isn't allowed or 0 */
63
+ if (res .a0 )
64
+ pr_warn ("%s(): SMC failed: %d\n" , __func__ , (int )res .a0 );
65
+
66
+ return (int )res .a0 ;
67
+ }
68
+
69
+ /* Read/Modify/Write a protected PMU register. */
70
+ static int tensor_sec_reg_rmw (void * context , unsigned int reg ,
71
+ unsigned int mask , unsigned int val )
72
+ {
73
+ struct arm_smccc_res res ;
74
+ unsigned long pmu_base = (unsigned long )context ;
75
+
76
+ arm_smccc_smc (TENSOR_SMC_PMU_SEC_REG , pmu_base + reg ,
77
+ TENSOR_PMUREG_RMW , mask , val , 0 , 0 , 0 , & res );
78
+
79
+ /* returns -EINVAL if access isn't allowed or 0 */
80
+ if (res .a0 )
81
+ pr_warn ("%s(): SMC failed: %d\n" , __func__ , (int )res .a0 );
82
+
83
+ return (int )res .a0 ;
84
+ }
85
+
86
+ /*
87
+ * Read a protected PMU register. All PMU registers can be read by Linux.
88
+ * Note: The SMC read register is not used, as only registers that can be
89
+ * written are readable via SMC.
90
+ */
91
+ static int tensor_sec_reg_read (void * context , unsigned int reg ,
92
+ unsigned int * val )
93
+ {
94
+ * val = pmu_raw_readl (reg );
95
+ return 0 ;
96
+ }
97
+
98
+ /*
99
+ * For SoCs that have set/clear bit hardware this function can be used when
100
+ * the PMU register will be accessed by multiple masters.
101
+ *
102
+ * For example, to set bits 13:8 in PMU reg offset 0x3e80
103
+ * tensor_set_bits_atomic(ctx, 0x3e80, 0x3f00, 0x3f00);
104
+ *
105
+ * Set bit 8, and clear bits 13:9 PMU reg offset 0x3e80
106
+ * tensor_set_bits_atomic(0x3e80, 0x100, 0x3f00);
107
+ */
108
+ static int tensor_set_bits_atomic (void * ctx , unsigned int offset , u32 val ,
109
+ u32 mask )
110
+ {
111
+ int ret ;
112
+ unsigned int i ;
113
+
114
+ for (i = 0 ; i < 32 ; i ++ ) {
115
+ if (!(mask & BIT (i )))
116
+ continue ;
117
+
118
+ offset &= ~TENSOR_SET_BITS ;
119
+
120
+ if (val & BIT (i ))
121
+ offset |= TENSOR_SET_BITS ;
122
+ else
123
+ offset |= TENSOR_CLR_BITS ;
124
+
125
+ ret = tensor_sec_reg_write (ctx , offset , i );
126
+ if (ret )
127
+ return ret ;
128
+ }
129
+ return ret ;
130
+ }
131
+
132
+ static int tensor_sec_update_bits (void * ctx , unsigned int reg ,
133
+ unsigned int mask , unsigned int val )
134
+ {
135
+ /*
136
+ * Use atomic operations for PMU_ALIVE registers (offset 0~0x3FFF)
137
+ * as the target registers can be accessed by multiple masters.
138
+ */
139
+ if (reg > PMUALIVE_MASK )
140
+ return tensor_sec_reg_rmw (ctx , reg , mask , val );
141
+
142
+ return tensor_set_bits_atomic (ctx , reg , val , mask );
143
+ }
28
144
29
145
void pmu_raw_writel (u32 val , u32 offset )
30
146
{
@@ -75,11 +191,41 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode)
75
191
#define exynos_pmu_data_arm_ptr (data ) NULL
76
192
#endif
77
193
194
+ static const struct regmap_config regmap_smccfg = {
195
+ .name = "pmu_regs" ,
196
+ .reg_bits = 32 ,
197
+ .reg_stride = 4 ,
198
+ .val_bits = 32 ,
199
+ .fast_io = true,
200
+ .use_single_read = true,
201
+ .use_single_write = true,
202
+ .reg_read = tensor_sec_reg_read ,
203
+ .reg_write = tensor_sec_reg_write ,
204
+ .reg_update_bits = tensor_sec_update_bits ,
205
+ };
206
+
207
+ static const struct regmap_config regmap_mmiocfg = {
208
+ .name = "pmu_regs" ,
209
+ .reg_bits = 32 ,
210
+ .reg_stride = 4 ,
211
+ .val_bits = 32 ,
212
+ .fast_io = true,
213
+ .use_single_read = true,
214
+ .use_single_write = true,
215
+ };
216
+
217
+ static const struct exynos_pmu_data gs101_pmu_data = {
218
+ .pmu_secure = true
219
+ };
220
+
78
221
/*
79
222
* PMU platform driver and devicetree bindings.
80
223
*/
81
224
static const struct of_device_id exynos_pmu_of_device_ids [] = {
82
225
{
226
+ .compatible = "google,gs101-pmu" ,
227
+ .data = & gs101_pmu_data ,
228
+ }, {
83
229
.compatible = "samsung,exynos3250-pmu" ,
84
230
.data = exynos_pmu_data_arm_ptr (exynos3250_pmu_data ),
85
231
}, {
@@ -113,19 +259,75 @@ static const struct mfd_cell exynos_pmu_devs[] = {
113
259
{ .name = "exynos-clkout" , },
114
260
};
115
261
262
+ /**
263
+ * exynos_get_pmu_regmap() - Obtain pmureg regmap
264
+ *
265
+ * Find the pmureg regmap previously configured in probe() and return regmap
266
+ * pointer.
267
+ *
268
+ * Return: A pointer to regmap if found or ERR_PTR error value.
269
+ */
116
270
struct regmap * exynos_get_pmu_regmap (void )
117
271
{
118
272
struct device_node * np = of_find_matching_node (NULL ,
119
273
exynos_pmu_of_device_ids );
120
274
if (np )
121
- return syscon_node_to_regmap (np );
275
+ return exynos_get_pmu_regmap_by_phandle (np , NULL );
122
276
return ERR_PTR (- ENODEV );
123
277
}
124
278
EXPORT_SYMBOL_GPL (exynos_get_pmu_regmap );
125
279
280
+ /**
281
+ * exynos_get_pmu_regmap_by_phandle() - Obtain pmureg regmap via phandle
282
+ * @np: Device node holding PMU phandle property
283
+ * @propname: Name of property holding phandle value
284
+ *
285
+ * Find the pmureg regmap previously configured in probe() and return regmap
286
+ * pointer.
287
+ *
288
+ * Return: A pointer to regmap if found or ERR_PTR error value.
289
+ */
290
+ struct regmap * exynos_get_pmu_regmap_by_phandle (struct device_node * np ,
291
+ const char * propname )
292
+ {
293
+ struct exynos_pmu_context * ctx ;
294
+ struct device_node * pmu_np ;
295
+ struct device * dev ;
296
+
297
+ if (propname )
298
+ pmu_np = of_parse_phandle (np , propname , 0 );
299
+ else
300
+ pmu_np = np ;
301
+
302
+ if (!pmu_np )
303
+ return ERR_PTR (- ENODEV );
304
+
305
+ /*
306
+ * Determine if exynos-pmu device has probed and therefore regmap
307
+ * has been created and can be returned to the caller. Otherwise we
308
+ * return -EPROBE_DEFER.
309
+ */
310
+ dev = driver_find_device_by_of_node (& exynos_pmu_driver .driver ,
311
+ (void * )pmu_np );
312
+
313
+ if (propname )
314
+ of_node_put (pmu_np );
315
+
316
+ if (!dev )
317
+ return ERR_PTR (- EPROBE_DEFER );
318
+
319
+ ctx = dev_get_drvdata (dev );
320
+
321
+ return ctx -> pmureg ;
322
+ }
323
+ EXPORT_SYMBOL_GPL (exynos_get_pmu_regmap_by_phandle );
324
+
126
325
static int exynos_pmu_probe (struct platform_device * pdev )
127
326
{
128
327
struct device * dev = & pdev -> dev ;
328
+ struct regmap_config pmu_regmcfg ;
329
+ struct regmap * regmap ;
330
+ struct resource * res ;
129
331
int ret ;
130
332
131
333
pmu_base_addr = devm_platform_ioremap_resource (pdev , 0 );
@@ -137,9 +339,38 @@ static int exynos_pmu_probe(struct platform_device *pdev)
137
339
GFP_KERNEL );
138
340
if (!pmu_context )
139
341
return - ENOMEM ;
140
- pmu_context -> dev = dev ;
342
+
343
+ res = platform_get_resource (pdev , IORESOURCE_MEM , 0 );
344
+ if (!res )
345
+ return - ENODEV ;
346
+
141
347
pmu_context -> pmu_data = of_device_get_match_data (dev );
142
348
349
+ /* For SoCs that secure PMU register writes use custom regmap */
350
+ if (pmu_context -> pmu_data && pmu_context -> pmu_data -> pmu_secure ) {
351
+ pmu_regmcfg = regmap_smccfg ;
352
+ pmu_regmcfg .max_register = resource_size (res ) -
353
+ pmu_regmcfg .reg_stride ;
354
+ /* Need physical address for SMC call */
355
+ regmap = devm_regmap_init (dev , NULL ,
356
+ (void * )(uintptr_t )res -> start ,
357
+ & pmu_regmcfg );
358
+ } else {
359
+ /* All other SoCs use a MMIO regmap */
360
+ pmu_regmcfg = regmap_mmiocfg ;
361
+ pmu_regmcfg .max_register = resource_size (res ) -
362
+ pmu_regmcfg .reg_stride ;
363
+ regmap = devm_regmap_init_mmio (dev , pmu_base_addr ,
364
+ & pmu_regmcfg );
365
+ }
366
+
367
+ if (IS_ERR (regmap ))
368
+ return dev_err_probe (& pdev -> dev , PTR_ERR (regmap ),
369
+ "regmap init failed\n" );
370
+
371
+ pmu_context -> pmureg = regmap ;
372
+ pmu_context -> dev = dev ;
373
+
143
374
if (pmu_context -> pmu_data && pmu_context -> pmu_data -> pmu_init )
144
375
pmu_context -> pmu_data -> pmu_init ();
145
376
0 commit comments