Linux-libre 5.4.49-gnu
[librecmc/linux-libre.git] / arch / powerpc / platforms / cell / cbe_thermal.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * thermal support for the cell processor
4  *
5  * This module adds some sysfs attributes to cpu and spu nodes.
6  * Base for measurements are the digital thermal sensors (DTS)
7  * located on the chip.
8  * The accuracy is 2 degrees, starting from 65 up to 125 degrees celsius
9  * The attributes can be found under
10  * /sys/devices/system/cpu/cpuX/thermal
11  * /sys/devices/system/spu/spuX/thermal
12  *
13  * The following attributes are added for each node:
14  * temperature:
15  *      contains the current temperature measured by the DTS
16  * throttle_begin:
17  *      throttling begins when temperature is greater or equal to
18  *      throttle_begin. Setting this value to 125 prevents throttling.
19  * throttle_end:
20  *      throttling is being ceased, if the temperature is lower than
21  *      throttle_end. Due to a delay between applying throttling and
22  *      a reduced temperature this value should be less than throttle_begin.
23  *      A value equal to throttle_begin provides only a very little hysteresis.
24  * throttle_full_stop:
25  *      If the temperatrue is greater or equal to throttle_full_stop,
26  *      full throttling is applied to the cpu or spu. This value should be
27  *      greater than throttle_begin and throttle_end. Setting this value to
28  *      65 prevents the unit from running code at all.
29  *
30  * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
31  *
32  * Author: Christian Krafft <krafft@de.ibm.com>
33  */
34
35 #include <linux/module.h>
36 #include <linux/device.h>
37 #include <linux/kernel.h>
38 #include <linux/cpu.h>
39 #include <linux/stringify.h>
40 #include <asm/spu.h>
41 #include <asm/io.h>
42 #include <asm/prom.h>
43 #include <asm/cell-regs.h>
44
45 #include "spu_priv1_mmio.h"
46
47 #define TEMP_MIN 65
48 #define TEMP_MAX 125
49
50 #define DEVICE_PREFIX_ATTR(_prefix,_name,_mode)                 \
51 struct device_attribute attr_ ## _prefix ## _ ## _name = {      \
52         .attr = { .name = __stringify(_name), .mode = _mode },  \
53         .show   = _prefix ## _show_ ## _name,                   \
54         .store  = _prefix ## _store_ ## _name,                  \
55 };
56
57 static inline u8 reg_to_temp(u8 reg_value)
58 {
59         return ((reg_value & 0x3f) << 1) + TEMP_MIN;
60 }
61
62 static inline u8 temp_to_reg(u8 temp)
63 {
64         return ((temp - TEMP_MIN) >> 1) & 0x3f;
65 }
66
67 static struct cbe_pmd_regs __iomem *get_pmd_regs(struct device *dev)
68 {
69         struct spu *spu;
70
71         spu = container_of(dev, struct spu, dev);
72
73         return cbe_get_pmd_regs(spu_devnode(spu));
74 }
75
76 /* returns the value for a given spu in a given register */
77 static u8 spu_read_register_value(struct device *dev, union spe_reg __iomem *reg)
78 {
79         union spe_reg value;
80         struct spu *spu;
81
82         spu = container_of(dev, struct spu, dev);
83         value.val = in_be64(&reg->val);
84
85         return value.spe[spu->spe_id];
86 }
87
88 static ssize_t spu_show_temp(struct device *dev, struct device_attribute *attr,
89                         char *buf)
90 {
91         u8 value;
92         struct cbe_pmd_regs __iomem *pmd_regs;
93
94         pmd_regs = get_pmd_regs(dev);
95
96         value = spu_read_register_value(dev, &pmd_regs->ts_ctsr1);
97
98         return sprintf(buf, "%d\n", reg_to_temp(value));
99 }
100
101 static ssize_t show_throttle(struct cbe_pmd_regs __iomem *pmd_regs, char *buf, int pos)
102 {
103         u64 value;
104
105         value = in_be64(&pmd_regs->tm_tpr.val);
106         /* access the corresponding byte */
107         value >>= pos;
108         value &= 0x3F;
109
110         return sprintf(buf, "%d\n", reg_to_temp(value));
111 }
112
113 static ssize_t store_throttle(struct cbe_pmd_regs __iomem *pmd_regs, const char *buf, size_t size, int pos)
114 {
115         u64 reg_value;
116         unsigned int temp;
117         u64 new_value;
118         int ret;
119
120         ret = sscanf(buf, "%u", &temp);
121
122         if (ret != 1 || temp < TEMP_MIN || temp > TEMP_MAX)
123                 return -EINVAL;
124
125         new_value = temp_to_reg(temp);
126
127         reg_value = in_be64(&pmd_regs->tm_tpr.val);
128
129         /* zero out bits for new value */
130         reg_value &= ~(0xffull << pos);
131         /* set bits to new value */
132         reg_value |= new_value << pos;
133
134         out_be64(&pmd_regs->tm_tpr.val, reg_value);
135         return size;
136 }
137
138 static ssize_t spu_show_throttle_end(struct device *dev,
139                         struct device_attribute *attr, char *buf)
140 {
141         return show_throttle(get_pmd_regs(dev), buf, 0);
142 }
143
144 static ssize_t spu_show_throttle_begin(struct device *dev,
145                         struct device_attribute *attr, char *buf)
146 {
147         return show_throttle(get_pmd_regs(dev), buf, 8);
148 }
149
150 static ssize_t spu_show_throttle_full_stop(struct device *dev,
151                         struct device_attribute *attr, char *buf)
152 {
153         return show_throttle(get_pmd_regs(dev), buf, 16);
154 }
155
156 static ssize_t spu_store_throttle_end(struct device *dev,
157                         struct device_attribute *attr, const char *buf, size_t size)
158 {
159         return store_throttle(get_pmd_regs(dev), buf, size, 0);
160 }
161
162 static ssize_t spu_store_throttle_begin(struct device *dev,
163                         struct device_attribute *attr, const char *buf, size_t size)
164 {
165         return store_throttle(get_pmd_regs(dev), buf, size, 8);
166 }
167
168 static ssize_t spu_store_throttle_full_stop(struct device *dev,
169                         struct device_attribute *attr, const char *buf, size_t size)
170 {
171         return store_throttle(get_pmd_regs(dev), buf, size, 16);
172 }
173
174 static ssize_t ppe_show_temp(struct device *dev, char *buf, int pos)
175 {
176         struct cbe_pmd_regs __iomem *pmd_regs;
177         u64 value;
178
179         pmd_regs = cbe_get_cpu_pmd_regs(dev->id);
180         value = in_be64(&pmd_regs->ts_ctsr2);
181
182         value = (value >> pos) & 0x3f;
183
184         return sprintf(buf, "%d\n", reg_to_temp(value));
185 }
186
187
188 /* shows the temperature of the DTS on the PPE,
189  * located near the linear thermal sensor */
190 static ssize_t ppe_show_temp0(struct device *dev,
191                         struct device_attribute *attr, char *buf)
192 {
193         return ppe_show_temp(dev, buf, 32);
194 }
195
196 /* shows the temperature of the second DTS on the PPE */
197 static ssize_t ppe_show_temp1(struct device *dev,
198                         struct device_attribute *attr, char *buf)
199 {
200         return ppe_show_temp(dev, buf, 0);
201 }
202
203 static ssize_t ppe_show_throttle_end(struct device *dev,
204                         struct device_attribute *attr, char *buf)
205 {
206         return show_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, 32);
207 }
208
209 static ssize_t ppe_show_throttle_begin(struct device *dev,
210                         struct device_attribute *attr, char *buf)
211 {
212         return show_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, 40);
213 }
214
215 static ssize_t ppe_show_throttle_full_stop(struct device *dev,
216                         struct device_attribute *attr, char *buf)
217 {
218         return show_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, 48);
219 }
220
221 static ssize_t ppe_store_throttle_end(struct device *dev,
222                         struct device_attribute *attr, const char *buf, size_t size)
223 {
224         return store_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, size, 32);
225 }
226
227 static ssize_t ppe_store_throttle_begin(struct device *dev,
228                         struct device_attribute *attr, const char *buf, size_t size)
229 {
230         return store_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, size, 40);
231 }
232
233 static ssize_t ppe_store_throttle_full_stop(struct device *dev,
234                         struct device_attribute *attr, const char *buf, size_t size)
235 {
236         return store_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, size, 48);
237 }
238
239
240 static struct device_attribute attr_spu_temperature = {
241         .attr = {.name = "temperature", .mode = 0400 },
242         .show = spu_show_temp,
243 };
244
245 static DEVICE_PREFIX_ATTR(spu, throttle_end, 0600);
246 static DEVICE_PREFIX_ATTR(spu, throttle_begin, 0600);
247 static DEVICE_PREFIX_ATTR(spu, throttle_full_stop, 0600);
248
249
250 static struct attribute *spu_attributes[] = {
251         &attr_spu_temperature.attr,
252         &attr_spu_throttle_end.attr,
253         &attr_spu_throttle_begin.attr,
254         &attr_spu_throttle_full_stop.attr,
255         NULL,
256 };
257
258 static struct attribute_group spu_attribute_group = {
259         .name   = "thermal",
260         .attrs  = spu_attributes,
261 };
262
263 static struct device_attribute attr_ppe_temperature0 = {
264         .attr = {.name = "temperature0", .mode = 0400 },
265         .show = ppe_show_temp0,
266 };
267
268 static struct device_attribute attr_ppe_temperature1 = {
269         .attr = {.name = "temperature1", .mode = 0400 },
270         .show = ppe_show_temp1,
271 };
272
273 static DEVICE_PREFIX_ATTR(ppe, throttle_end, 0600);
274 static DEVICE_PREFIX_ATTR(ppe, throttle_begin, 0600);
275 static DEVICE_PREFIX_ATTR(ppe, throttle_full_stop, 0600);
276
277 static struct attribute *ppe_attributes[] = {
278         &attr_ppe_temperature0.attr,
279         &attr_ppe_temperature1.attr,
280         &attr_ppe_throttle_end.attr,
281         &attr_ppe_throttle_begin.attr,
282         &attr_ppe_throttle_full_stop.attr,
283         NULL,
284 };
285
286 static struct attribute_group ppe_attribute_group = {
287         .name   = "thermal",
288         .attrs  = ppe_attributes,
289 };
290
291 /*
292  * initialize throttling with default values
293  */
294 static int __init init_default_values(void)
295 {
296         int cpu;
297         struct cbe_pmd_regs __iomem *pmd_regs;
298         struct device *dev;
299         union ppe_spe_reg tpr;
300         union spe_reg str1;
301         u64 str2;
302         union spe_reg cr1;
303         u64 cr2;
304
305         /* TPR defaults */
306         /* ppe
307          *      1F - no full stop
308          *      08 - dynamic throttling starts if over 80 degrees
309          *      03 - dynamic throttling ceases if below 70 degrees */
310         tpr.ppe = 0x1F0803;
311         /* spe
312          *      10 - full stopped when over 96 degrees
313          *      08 - dynamic throttling starts if over 80 degrees
314          *      03 - dynamic throttling ceases if below 70 degrees
315          */
316         tpr.spe = 0x100803;
317
318         /* STR defaults */
319         /* str1
320          *      10 - stop 16 of 32 cycles
321          */
322         str1.val = 0x1010101010101010ull;
323         /* str2
324          *      10 - stop 16 of 32 cycles
325          */
326         str2 = 0x10;
327
328         /* CR defaults */
329         /* cr1
330          *      4 - normal operation
331          */
332         cr1.val = 0x0404040404040404ull;
333         /* cr2
334          *      4 - normal operation
335          */
336         cr2 = 0x04;
337
338         for_each_possible_cpu (cpu) {
339                 pr_debug("processing cpu %d\n", cpu);
340                 dev = get_cpu_device(cpu);
341
342                 if (!dev) {
343                         pr_info("invalid dev pointer for cbe_thermal\n");
344                         return -EINVAL;
345                 }
346
347                 pmd_regs = cbe_get_cpu_pmd_regs(dev->id);
348
349                 if (!pmd_regs) {
350                         pr_info("invalid CBE regs pointer for cbe_thermal\n");
351                         return -EINVAL;
352                 }
353
354                 out_be64(&pmd_regs->tm_str2, str2);
355                 out_be64(&pmd_regs->tm_str1.val, str1.val);
356                 out_be64(&pmd_regs->tm_tpr.val, tpr.val);
357                 out_be64(&pmd_regs->tm_cr1.val, cr1.val);
358                 out_be64(&pmd_regs->tm_cr2, cr2);
359         }
360
361         return 0;
362 }
363
364
365 static int __init thermal_init(void)
366 {
367         int rc = init_default_values();
368
369         if (rc == 0) {
370                 spu_add_dev_attr_group(&spu_attribute_group);
371                 cpu_add_dev_attr_group(&ppe_attribute_group);
372         }
373
374         return rc;
375 }
376 module_init(thermal_init);
377
378 static void __exit thermal_exit(void)
379 {
380         spu_remove_dev_attr_group(&spu_attribute_group);
381         cpu_remove_dev_attr_group(&ppe_attribute_group);
382 }
383 module_exit(thermal_exit);
384
385 MODULE_LICENSE("GPL");
386 MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
387