]>
Commit | Line | Data |
---|---|---|
b3d7dc19 CK |
1 | /* |
2 | * thermal support for the cell processor | |
3 | * | |
4 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 | |
5 | * | |
6 | * Author: Christian Krafft <krafft@de.ibm.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2, or (at your option) | |
11 | * any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
21 | */ | |
22 | ||
23 | #include <linux/module.h> | |
24 | #include <linux/sysdev.h> | |
25 | #include <linux/kernel.h> | |
26 | #include <linux/cpu.h> | |
27 | #include <asm/spu.h> | |
28 | #include <asm/io.h> | |
29 | #include <asm/prom.h> | |
30 | ||
31 | #include "cbe_regs.h" | |
e28b0031 | 32 | #include "spu_priv1_mmio.h" |
b3d7dc19 CK |
33 | |
34 | static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev) | |
35 | { | |
36 | struct spu *spu; | |
37 | ||
38 | spu = container_of(sysdev, struct spu, sysdev); | |
39 | ||
e28b0031 | 40 | return cbe_get_pmd_regs(spu_devnode(spu)); |
b3d7dc19 CK |
41 | } |
42 | ||
43 | /* returns the value for a given spu in a given register */ | |
44 | static u8 spu_read_register_value(struct sys_device *sysdev, union spe_reg __iomem *reg) | |
45 | { | |
e2eb6392 | 46 | const unsigned int *id; |
b3d7dc19 CK |
47 | union spe_reg value; |
48 | struct spu *spu; | |
49 | ||
50 | /* getting the id from the reg attribute will not work on future device-tree layouts | |
51 | * in future we should store the id to the spu struct and use it here */ | |
52 | spu = container_of(sysdev, struct spu, sysdev); | |
e2eb6392 | 53 | id = of_get_property(spu_devnode(spu), "reg", NULL); |
b3d7dc19 CK |
54 | value.val = in_be64(®->val); |
55 | ||
56 | return value.spe[*id]; | |
57 | } | |
58 | ||
59 | static ssize_t spu_show_temp(struct sys_device *sysdev, char *buf) | |
60 | { | |
61 | int value; | |
62 | struct cbe_pmd_regs __iomem *pmd_regs; | |
63 | ||
64 | pmd_regs = get_pmd_regs(sysdev); | |
65 | ||
66 | value = spu_read_register_value(sysdev, &pmd_regs->ts_ctsr1); | |
67 | /* clear all other bits */ | |
68 | value &= 0x3F; | |
69 | /* temp is stored in steps of 2 degrees */ | |
70 | value *= 2; | |
71 | /* base temp is 65 degrees */ | |
72 | value += 65; | |
73 | ||
74 | return sprintf(buf, "%d\n", (int) value); | |
75 | } | |
76 | ||
77 | static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos) | |
78 | { | |
79 | struct cbe_pmd_regs __iomem *pmd_regs; | |
80 | u64 value; | |
81 | ||
82 | pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id); | |
83 | value = in_be64(&pmd_regs->ts_ctsr2); | |
84 | ||
85 | /* access the corresponding byte */ | |
86 | value >>= pos; | |
87 | /* clear all other bits */ | |
88 | value &= 0x3F; | |
89 | /* temp is stored in steps of 2 degrees */ | |
90 | value *= 2; | |
91 | /* base temp is 65 degrees */ | |
92 | value += 65; | |
93 | ||
94 | return sprintf(buf, "%d\n", (int) value); | |
95 | } | |
96 | ||
97 | ||
98 | /* shows the temperature of the DTS on the PPE, | |
99 | * located near the linear thermal sensor */ | |
100 | static ssize_t ppe_show_temp0(struct sys_device *sysdev, char *buf) | |
101 | { | |
102 | return ppe_show_temp(sysdev, buf, 32); | |
103 | } | |
104 | ||
105 | /* shows the temperature of the second DTS on the PPE */ | |
106 | static ssize_t ppe_show_temp1(struct sys_device *sysdev, char *buf) | |
107 | { | |
108 | return ppe_show_temp(sysdev, buf, 0); | |
109 | } | |
110 | ||
111 | static struct sysdev_attribute attr_spu_temperature = { | |
112 | .attr = {.name = "temperature", .mode = 0400 }, | |
113 | .show = spu_show_temp, | |
114 | }; | |
115 | ||
116 | static struct attribute *spu_attributes[] = { | |
117 | &attr_spu_temperature.attr, | |
22b6e590 | 118 | NULL, |
b3d7dc19 CK |
119 | }; |
120 | ||
121 | static struct attribute_group spu_attribute_group = { | |
122 | .name = "thermal", | |
123 | .attrs = spu_attributes, | |
124 | }; | |
125 | ||
126 | static struct sysdev_attribute attr_ppe_temperature0 = { | |
127 | .attr = {.name = "temperature0", .mode = 0400 }, | |
128 | .show = ppe_show_temp0, | |
129 | }; | |
130 | ||
131 | static struct sysdev_attribute attr_ppe_temperature1 = { | |
132 | .attr = {.name = "temperature1", .mode = 0400 }, | |
133 | .show = ppe_show_temp1, | |
134 | }; | |
135 | ||
136 | static struct attribute *ppe_attributes[] = { | |
137 | &attr_ppe_temperature0.attr, | |
138 | &attr_ppe_temperature1.attr, | |
22b6e590 | 139 | NULL, |
b3d7dc19 CK |
140 | }; |
141 | ||
142 | static struct attribute_group ppe_attribute_group = { | |
143 | .name = "thermal", | |
144 | .attrs = ppe_attributes, | |
145 | }; | |
146 | ||
147 | /* | |
148 | * initialize throttling with default values | |
149 | */ | |
150 | static void __init init_default_values(void) | |
151 | { | |
152 | int cpu; | |
153 | struct cbe_pmd_regs __iomem *pmd_regs; | |
154 | struct sys_device *sysdev; | |
155 | union ppe_spe_reg tpr; | |
156 | union spe_reg str1; | |
157 | u64 str2; | |
158 | union spe_reg cr1; | |
159 | u64 cr2; | |
160 | ||
161 | /* TPR defaults */ | |
162 | /* ppe | |
163 | * 1F - no full stop | |
164 | * 08 - dynamic throttling starts if over 80 degrees | |
165 | * 03 - dynamic throttling ceases if below 70 degrees */ | |
166 | tpr.ppe = 0x1F0803; | |
167 | /* spe | |
168 | * 10 - full stopped when over 96 degrees | |
169 | * 08 - dynamic throttling starts if over 80 degrees | |
170 | * 03 - dynamic throttling ceases if below 70 degrees | |
171 | */ | |
172 | tpr.spe = 0x100803; | |
173 | ||
174 | /* STR defaults */ | |
175 | /* str1 | |
176 | * 10 - stop 16 of 32 cycles | |
177 | */ | |
178 | str1.val = 0x1010101010101010ull; | |
179 | /* str2 | |
180 | * 10 - stop 16 of 32 cycles | |
181 | */ | |
182 | str2 = 0x10; | |
183 | ||
184 | /* CR defaults */ | |
185 | /* cr1 | |
186 | * 4 - normal operation | |
187 | */ | |
188 | cr1.val = 0x0404040404040404ull; | |
189 | /* cr2 | |
190 | * 4 - normal operation | |
191 | */ | |
192 | cr2 = 0x04; | |
193 | ||
194 | for_each_possible_cpu (cpu) { | |
195 | pr_debug("processing cpu %d\n", cpu); | |
196 | sysdev = get_cpu_sysdev(cpu); | |
197 | pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id); | |
198 | ||
199 | out_be64(&pmd_regs->tm_str2, str2); | |
200 | out_be64(&pmd_regs->tm_str1.val, str1.val); | |
201 | out_be64(&pmd_regs->tm_tpr.val, tpr.val); | |
202 | out_be64(&pmd_regs->tm_cr1.val, cr1.val); | |
203 | out_be64(&pmd_regs->tm_cr2, cr2); | |
204 | } | |
205 | } | |
206 | ||
207 | ||
208 | static int __init thermal_init(void) | |
209 | { | |
210 | init_default_values(); | |
211 | ||
212 | spu_add_sysdev_attr_group(&spu_attribute_group); | |
213 | cpu_add_sysdev_attr_group(&ppe_attribute_group); | |
214 | ||
215 | return 0; | |
216 | } | |
217 | module_init(thermal_init); | |
218 | ||
219 | static void __exit thermal_exit(void) | |
220 | { | |
221 | spu_remove_sysdev_attr_group(&spu_attribute_group); | |
222 | cpu_remove_sysdev_attr_group(&ppe_attribute_group); | |
223 | } | |
224 | module_exit(thermal_exit); | |
225 | ||
226 | MODULE_LICENSE("GPL"); | |
227 | MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>"); | |
228 |