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