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(®->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