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 
388