Commit | Line | Data |
---|---|---|
34e9d85a MP |
1 | /* |
2 | * Copyright 2010 PathScale inc. | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
20 | * OTHER DEALINGS IN THE SOFTWARE. | |
21 | * | |
22 | * Authors: Martin Peres | |
23 | */ | |
24 | ||
25 | #include "drmP.h" | |
26 | ||
27 | #include "nouveau_drv.h" | |
28 | #include "nouveau_pm.h" | |
29 | ||
5c4abd09 | 30 | static void |
34e9d85a MP |
31 | nouveau_temp_vbios_parse(struct drm_device *dev, u8 *temp) |
32 | { | |
33 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
34 | struct nouveau_pm_engine *pm = &dev_priv->engine.pm; | |
35 | struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants; | |
36 | struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp; | |
37 | int i, headerlen, recordlen, entries; | |
38 | ||
39 | if (!temp) { | |
40 | NV_DEBUG(dev, "temperature table pointer invalid\n"); | |
41 | return; | |
42 | } | |
43 | ||
44 | /* Set the default sensor's contants */ | |
45 | sensor->offset_constant = 0; | |
46 | sensor->offset_mult = 1; | |
47 | sensor->offset_div = 1; | |
48 | sensor->slope_mult = 1; | |
49 | sensor->slope_div = 1; | |
50 | ||
51 | /* Set the default temperature thresholds */ | |
52 | temps->critical = 110; | |
53 | temps->down_clock = 100; | |
54 | temps->fan_boost = 90; | |
55 | ||
56 | /* Set the known default values to setup the temperature sensor */ | |
57 | if (dev_priv->card_type >= NV_40) { | |
58 | switch (dev_priv->chipset) { | |
59 | case 0x43: | |
60 | sensor->offset_mult = 32060; | |
61 | sensor->offset_div = 1000; | |
62 | sensor->slope_mult = 792; | |
63 | sensor->slope_div = 1000; | |
64 | break; | |
65 | ||
66 | case 0x44: | |
67 | case 0x47: | |
d34ec507 | 68 | case 0x4a: |
34e9d85a MP |
69 | sensor->offset_mult = 27839; |
70 | sensor->offset_div = 1000; | |
71 | sensor->slope_mult = 780; | |
72 | sensor->slope_div = 1000; | |
73 | break; | |
74 | ||
75 | case 0x46: | |
76 | sensor->offset_mult = -24775; | |
77 | sensor->offset_div = 100; | |
78 | sensor->slope_mult = 467; | |
79 | sensor->slope_div = 10000; | |
80 | break; | |
81 | ||
82 | case 0x49: | |
83 | sensor->offset_mult = -25051; | |
84 | sensor->offset_div = 100; | |
85 | sensor->slope_mult = 458; | |
86 | sensor->slope_div = 10000; | |
87 | break; | |
88 | ||
89 | case 0x4b: | |
90 | sensor->offset_mult = -24088; | |
91 | sensor->offset_div = 100; | |
92 | sensor->slope_mult = 442; | |
93 | sensor->slope_div = 10000; | |
94 | break; | |
95 | ||
96 | case 0x50: | |
97 | sensor->offset_mult = -22749; | |
98 | sensor->offset_div = 100; | |
99 | sensor->slope_mult = 431; | |
100 | sensor->slope_div = 10000; | |
101 | break; | |
102 | } | |
103 | } | |
104 | ||
105 | headerlen = temp[1]; | |
106 | recordlen = temp[2]; | |
107 | entries = temp[3]; | |
108 | temp = temp + headerlen; | |
109 | ||
110 | /* Read the entries from the table */ | |
111 | for (i = 0; i < entries; i++) { | |
112 | u16 value = ROM16(temp[1]); | |
113 | ||
114 | switch (temp[0]) { | |
115 | case 0x01: | |
67e1d4fb FJ |
116 | if ((value & 0x8f) == 0) |
117 | sensor->offset_constant = (value >> 9) & 0x7f; | |
34e9d85a MP |
118 | break; |
119 | ||
120 | case 0x04: | |
121 | if ((value & 0xf00f) == 0xa000) /* core */ | |
122 | temps->critical = (value&0x0ff0) >> 4; | |
123 | break; | |
124 | ||
125 | case 0x07: | |
126 | if ((value & 0xf00f) == 0xa000) /* core */ | |
127 | temps->down_clock = (value&0x0ff0) >> 4; | |
128 | break; | |
129 | ||
130 | case 0x08: | |
131 | if ((value & 0xf00f) == 0xa000) /* core */ | |
132 | temps->fan_boost = (value&0x0ff0) >> 4; | |
133 | break; | |
134 | ||
135 | case 0x10: | |
136 | sensor->offset_mult = value; | |
137 | break; | |
138 | ||
139 | case 0x11: | |
140 | sensor->offset_div = value; | |
141 | break; | |
142 | ||
143 | case 0x12: | |
144 | sensor->slope_mult = value; | |
145 | break; | |
146 | ||
147 | case 0x13: | |
148 | sensor->slope_div = value; | |
149 | break; | |
150 | } | |
151 | temp += recordlen; | |
152 | } | |
153 | ||
154 | nouveau_temp_safety_checks(dev); | |
155 | } | |
156 | ||
8155cac4 FJ |
157 | static int |
158 | nv40_sensor_setup(struct drm_device *dev) | |
34e9d85a MP |
159 | { |
160 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
161 | struct nouveau_pm_engine *pm = &dev_priv->engine.pm; | |
162 | struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants; | |
163 | u32 offset = sensor->offset_mult / sensor->offset_div; | |
164 | u32 sensor_calibration; | |
165 | ||
166 | /* set up the sensors */ | |
167 | sensor_calibration = 120 - offset - sensor->offset_constant; | |
168 | sensor_calibration = sensor_calibration * sensor->slope_div / | |
169 | sensor->slope_mult; | |
170 | ||
171 | if (dev_priv->chipset >= 0x46) | |
172 | sensor_calibration |= 0x80000000; | |
173 | else | |
174 | sensor_calibration |= 0x10000000; | |
175 | ||
176 | nv_wr32(dev, 0x0015b0, sensor_calibration); | |
177 | ||
178 | /* Wait for the sensor to update */ | |
179 | msleep(5); | |
180 | ||
181 | /* read */ | |
4164743c | 182 | return nv_rd32(dev, 0x0015b4) & 0x1fff; |
34e9d85a MP |
183 | } |
184 | ||
8155cac4 FJ |
185 | int |
186 | nv40_temp_get(struct drm_device *dev) | |
34e9d85a MP |
187 | { |
188 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
189 | struct nouveau_pm_engine *pm = &dev_priv->engine.pm; | |
190 | struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants; | |
8155cac4 FJ |
191 | int offset = sensor->offset_mult / sensor->offset_div; |
192 | int core_temp; | |
34e9d85a | 193 | |
8155cac4 FJ |
194 | if (dev_priv->chipset >= 0x50) { |
195 | core_temp = nv_rd32(dev, 0x20008); | |
34e9d85a | 196 | } else { |
8155cac4 FJ |
197 | core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff; |
198 | /* Setup the sensor if the temperature is 0 */ | |
199 | if (core_temp == 0) | |
200 | core_temp = nv40_sensor_setup(dev); | |
34e9d85a MP |
201 | } |
202 | ||
8155cac4 FJ |
203 | core_temp = core_temp * sensor->slope_mult / sensor->slope_div; |
204 | core_temp = core_temp + offset + sensor->offset_constant; | |
205 | ||
206 | return core_temp; | |
207 | } | |
208 | ||
209 | int | |
210 | nv84_temp_get(struct drm_device *dev) | |
211 | { | |
212 | return nv_rd32(dev, 0x20400); | |
34e9d85a MP |
213 | } |
214 | ||
215 | void | |
216 | nouveau_temp_safety_checks(struct drm_device *dev) | |
217 | { | |
218 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
219 | struct nouveau_pm_engine *pm = &dev_priv->engine.pm; | |
220 | struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp; | |
221 | ||
222 | if (temps->critical > 120) | |
223 | temps->critical = 120; | |
224 | else if (temps->critical < 80) | |
225 | temps->critical = 80; | |
226 | ||
227 | if (temps->down_clock > 110) | |
228 | temps->down_clock = 110; | |
229 | else if (temps->down_clock < 60) | |
230 | temps->down_clock = 60; | |
231 | ||
232 | if (temps->fan_boost > 100) | |
233 | temps->fan_boost = 100; | |
234 | else if (temps->fan_boost < 40) | |
235 | temps->fan_boost = 40; | |
236 | } | |
237 | ||
66146da0 FJ |
238 | static bool |
239 | probe_monitoring_device(struct nouveau_i2c_chan *i2c, | |
240 | struct i2c_board_info *info) | |
241 | { | |
242 | char modalias[16] = "i2c:"; | |
243 | struct i2c_client *client; | |
244 | ||
245 | strlcat(modalias, info->type, sizeof(modalias)); | |
246 | request_module(modalias); | |
247 | ||
248 | client = i2c_new_device(&i2c->adapter, info); | |
249 | if (!client) | |
250 | return false; | |
251 | ||
252 | if (!client->driver || client->driver->detect(client, info)) { | |
253 | i2c_unregister_device(client); | |
254 | return false; | |
255 | } | |
256 | ||
257 | return true; | |
258 | } | |
259 | ||
260 | static void | |
261 | nouveau_temp_probe_i2c(struct drm_device *dev) | |
262 | { | |
263 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
264 | struct dcb_table *dcb = &dev_priv->vbios.dcb; | |
265 | struct i2c_board_info info[] = { | |
266 | { I2C_BOARD_INFO("w83l785ts", 0x2d) }, | |
267 | { I2C_BOARD_INFO("w83781d", 0x2d) }, | |
268 | { I2C_BOARD_INFO("f75375", 0x2e) }, | |
269 | { I2C_BOARD_INFO("adt7473", 0x2e) }, | |
270 | { I2C_BOARD_INFO("lm99", 0x4c) }, | |
271 | { } | |
272 | }; | |
273 | int idx = (dcb->version >= 0x40 ? | |
274 | dcb->i2c_default_indices & 0xf : 2); | |
275 | ||
276 | nouveau_i2c_identify(dev, "monitoring device", info, | |
277 | probe_monitoring_device, idx); | |
278 | } | |
279 | ||
34e9d85a MP |
280 | void |
281 | nouveau_temp_init(struct drm_device *dev) | |
282 | { | |
283 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
284 | struct nvbios *bios = &dev_priv->vbios; | |
285 | struct bit_entry P; | |
286 | u8 *temp = NULL; | |
287 | ||
288 | if (bios->type == NVBIOS_BIT) { | |
289 | if (bit_table(dev, 'P', &P)) | |
290 | return; | |
291 | ||
292 | if (P.version == 1) | |
293 | temp = ROMPTR(bios, P.data[12]); | |
294 | else if (P.version == 2) | |
295 | temp = ROMPTR(bios, P.data[16]); | |
296 | else | |
297 | NV_WARN(dev, "unknown temp for BIT P %d\n", P.version); | |
66146da0 FJ |
298 | |
299 | nouveau_temp_vbios_parse(dev, temp); | |
34e9d85a MP |
300 | } |
301 | ||
66146da0 | 302 | nouveau_temp_probe_i2c(dev); |
34e9d85a MP |
303 | } |
304 | ||
305 | void | |
306 | nouveau_temp_fini(struct drm_device *dev) | |
307 | { | |
308 | ||
309 | } |