]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/nouveau/nouveau_temp.c
0f5a301605569988231365f48af9cab73a9bce2f
[karo-tx-linux.git] / drivers / gpu / drm / nouveau / nouveau_temp.c
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 <linux/module.h>
26
27 #include "drmP.h"
28
29 #include "nouveau_drv.h"
30 #include "nouveau_pm.h"
31
32 static void
33 nouveau_temp_vbios_parse(struct drm_device *dev, u8 *temp)
34 {
35         struct drm_nouveau_private *dev_priv = dev->dev_private;
36         struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
37         struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
38         struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
39         int i, headerlen, recordlen, entries;
40
41         if (!temp) {
42                 NV_DEBUG(dev, "temperature table pointer invalid\n");
43                 return;
44         }
45
46         /* Set the default sensor's contants */
47         sensor->offset_constant = 0;
48         sensor->offset_mult = 0;
49         sensor->offset_div = 1;
50         sensor->slope_mult = 1;
51         sensor->slope_div = 1;
52
53         /* Set the default temperature thresholds */
54         temps->critical = 110;
55         temps->down_clock = 100;
56         temps->fan_boost = 90;
57
58         /* Set the default range for the pwm fan */
59         pm->fan.min_duty = 30;
60         pm->fan.max_duty = 100;
61
62         /* Set the known default values to setup the temperature sensor */
63         if (dev_priv->card_type >= NV_40) {
64                 switch (dev_priv->chipset) {
65                 case 0x43:
66                         sensor->offset_mult = 32060;
67                         sensor->offset_div = 1000;
68                         sensor->slope_mult = 792;
69                         sensor->slope_div = 1000;
70                         break;
71
72                 case 0x44:
73                 case 0x47:
74                 case 0x4a:
75                         sensor->offset_mult = 27839;
76                         sensor->offset_div = 1000;
77                         sensor->slope_mult = 780;
78                         sensor->slope_div = 1000;
79                         break;
80
81                 case 0x46:
82                         sensor->offset_mult = -24775;
83                         sensor->offset_div = 100;
84                         sensor->slope_mult = 467;
85                         sensor->slope_div = 10000;
86                         break;
87
88                 case 0x49:
89                         sensor->offset_mult = -25051;
90                         sensor->offset_div = 100;
91                         sensor->slope_mult = 458;
92                         sensor->slope_div = 10000;
93                         break;
94
95                 case 0x4b:
96                         sensor->offset_mult = -24088;
97                         sensor->offset_div = 100;
98                         sensor->slope_mult = 442;
99                         sensor->slope_div = 10000;
100                         break;
101
102                 case 0x50:
103                         sensor->offset_mult = -22749;
104                         sensor->offset_div = 100;
105                         sensor->slope_mult = 431;
106                         sensor->slope_div = 10000;
107                         break;
108
109                 case 0x67:
110                         sensor->offset_mult = -26149;
111                         sensor->offset_div = 100;
112                         sensor->slope_mult = 484;
113                         sensor->slope_div = 10000;
114                         break;
115                 }
116         }
117
118         headerlen = temp[1];
119         recordlen = temp[2];
120         entries = temp[3];
121         temp = temp + headerlen;
122
123         /* Read the entries from the table */
124         for (i = 0; i < entries; i++) {
125                 s16 value = ROM16(temp[1]);
126
127                 switch (temp[0]) {
128                 case 0x01:
129                         if ((value & 0x8f) == 0)
130                                 sensor->offset_constant = (value >> 9) & 0x7f;
131                         break;
132
133                 case 0x04:
134                         if ((value & 0xf00f) == 0xa000) /* core */
135                                 temps->critical = (value&0x0ff0) >> 4;
136                         break;
137
138                 case 0x07:
139                         if ((value & 0xf00f) == 0xa000) /* core */
140                                 temps->down_clock = (value&0x0ff0) >> 4;
141                         break;
142
143                 case 0x08:
144                         if ((value & 0xf00f) == 0xa000) /* core */
145                                 temps->fan_boost = (value&0x0ff0) >> 4;
146                         break;
147
148                 case 0x10:
149                         sensor->offset_mult = value;
150                         break;
151
152                 case 0x11:
153                         sensor->offset_div = value;
154                         break;
155
156                 case 0x12:
157                         sensor->slope_mult = value;
158                         break;
159
160                 case 0x13:
161                         sensor->slope_div = value;
162                         break;
163                 case 0x22:
164                         pm->fan.min_duty = value & 0xff;
165                         pm->fan.max_duty = (value & 0xff00) >> 8;
166                         break;
167                 case 0x26:
168                         pm->fan.pwm_freq = value;
169                         break;
170                 }
171                 temp += recordlen;
172         }
173
174         nouveau_temp_safety_checks(dev);
175
176         /* check the fan min/max settings */
177         if (pm->fan.min_duty < 10)
178                 pm->fan.min_duty = 10;
179         if (pm->fan.max_duty > 100)
180                 pm->fan.max_duty = 100;
181         if (pm->fan.max_duty < pm->fan.min_duty)
182                 pm->fan.max_duty = pm->fan.min_duty;
183 }
184
185 static int
186 nv40_sensor_setup(struct drm_device *dev)
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;
191         s32 offset = sensor->offset_mult / sensor->offset_div;
192         s32 sensor_calibration;
193
194         /* set up the sensors */
195         sensor_calibration = 120 - offset - sensor->offset_constant;
196         sensor_calibration = sensor_calibration * sensor->slope_div /
197                                 sensor->slope_mult;
198
199         if (dev_priv->chipset >= 0x46)
200                 sensor_calibration |= 0x80000000;
201         else
202                 sensor_calibration |= 0x10000000;
203
204         nv_wr32(dev, 0x0015b0, sensor_calibration);
205
206         /* Wait for the sensor to update */
207         msleep(5);
208
209         /* read */
210         return nv_rd32(dev, 0x0015b4) & 0x1fff;
211 }
212
213 int
214 nv40_temp_get(struct drm_device *dev)
215 {
216         struct drm_nouveau_private *dev_priv = dev->dev_private;
217         struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
218         struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
219         int offset = sensor->offset_mult / sensor->offset_div;
220         int core_temp;
221
222         if (dev_priv->card_type >= NV_50) {
223                 core_temp = nv_rd32(dev, 0x20008);
224         } else {
225                 core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff;
226                 /* Setup the sensor if the temperature is 0 */
227                 if (core_temp == 0)
228                         core_temp = nv40_sensor_setup(dev);
229         }
230
231         core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
232         core_temp = core_temp + offset + sensor->offset_constant;
233
234         return core_temp;
235 }
236
237 int
238 nv84_temp_get(struct drm_device *dev)
239 {
240         return nv_rd32(dev, 0x20400);
241 }
242
243 void
244 nouveau_temp_safety_checks(struct drm_device *dev)
245 {
246         struct drm_nouveau_private *dev_priv = dev->dev_private;
247         struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
248         struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
249
250         if (temps->critical > 120)
251                 temps->critical = 120;
252         else if (temps->critical < 80)
253                 temps->critical = 80;
254
255         if (temps->down_clock > 110)
256                 temps->down_clock = 110;
257         else if (temps->down_clock < 60)
258                 temps->down_clock = 60;
259
260         if (temps->fan_boost > 100)
261                 temps->fan_boost = 100;
262         else if (temps->fan_boost < 40)
263                 temps->fan_boost = 40;
264 }
265
266 static bool
267 probe_monitoring_device(struct nouveau_i2c_chan *i2c,
268                         struct i2c_board_info *info)
269 {
270         struct i2c_client *client;
271
272         request_module("%s%s", I2C_MODULE_PREFIX, info->type);
273
274         client = i2c_new_device(&i2c->adapter, info);
275         if (!client)
276                 return false;
277
278         if (!client->driver || client->driver->detect(client, info)) {
279                 i2c_unregister_device(client);
280                 return false;
281         }
282
283         return true;
284 }
285
286 static void
287 nouveau_temp_probe_i2c(struct drm_device *dev)
288 {
289         struct i2c_board_info info[] = {
290                 { I2C_BOARD_INFO("w83l785ts", 0x2d) },
291                 { I2C_BOARD_INFO("w83781d", 0x2d) },
292                 { I2C_BOARD_INFO("adt7473", 0x2e) },
293                 { I2C_BOARD_INFO("f75375", 0x2e) },
294                 { I2C_BOARD_INFO("lm99", 0x4c) },
295                 { }
296         };
297
298         nouveau_i2c_identify(dev, "monitoring device", info,
299                              probe_monitoring_device, NV_I2C_DEFAULT(0));
300 }
301
302 void
303 nouveau_temp_init(struct drm_device *dev)
304 {
305         struct drm_nouveau_private *dev_priv = dev->dev_private;
306         struct nvbios *bios = &dev_priv->vbios;
307         struct bit_entry P;
308         u8 *temp = NULL;
309
310         if (bios->type == NVBIOS_BIT) {
311                 if (bit_table(dev, 'P', &P))
312                         return;
313
314                 if (P.version == 1)
315                         temp = ROMPTR(dev, P.data[12]);
316                 else if (P.version == 2)
317                         temp = ROMPTR(dev, P.data[16]);
318                 else
319                         NV_WARN(dev, "unknown temp for BIT P %d\n", P.version);
320
321                 nouveau_temp_vbios_parse(dev, temp);
322         }
323
324         nouveau_temp_probe_i2c(dev);
325 }
326
327 void
328 nouveau_temp_fini(struct drm_device *dev)
329 {
330
331 }