]> git.karo-electronics.de Git - linux-beck.git/blob - drivers/gpu/drm/nouveau/nouveau_temp.c
drm/nouveau: Add temperature support (vbios parsing, readings, hwmon)
[linux-beck.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 "drmP.h"
26
27 #include "nouveau_drv.h"
28 #include "nouveau_pm.h"
29
30 void
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:
68                         sensor->offset_mult = 27839;
69                         sensor->offset_div = 1000;
70                         sensor->slope_mult = 780;
71                         sensor->slope_div = 1000;
72                         break;
73
74                 case 0x46:
75                         sensor->offset_mult = -24775;
76                         sensor->offset_div = 100;
77                         sensor->slope_mult = 467;
78                         sensor->slope_div = 10000;
79                         break;
80
81                 case 0x49:
82                         sensor->offset_mult = -25051;
83                         sensor->offset_div = 100;
84                         sensor->slope_mult = 458;
85                         sensor->slope_div = 10000;
86                         break;
87
88                 case 0x4b:
89                         sensor->offset_mult = -24088;
90                         sensor->offset_div = 100;
91                         sensor->slope_mult = 442;
92                         sensor->slope_div = 10000;
93                         break;
94
95                 case 0x50:
96                         sensor->offset_mult = -22749;
97                         sensor->offset_div = 100;
98                         sensor->slope_mult = 431;
99                         sensor->slope_div = 10000;
100                         break;
101                 }
102         }
103
104         headerlen = temp[1];
105         recordlen = temp[2];
106         entries = temp[3];
107         temp = temp + headerlen;
108
109         /* Read the entries from the table */
110         for (i = 0; i < entries; i++) {
111                 u16 value = ROM16(temp[1]);
112
113                 switch (temp[0]) {
114                 case 0x01:
115                         value = (value&0x8f) == 0 ? (value >> 9) & 0x7f : 0;
116                         sensor->offset_constant = value;
117                         break;
118
119                 case 0x04:
120                         if ((value & 0xf00f) == 0xa000) /* core */
121                                 temps->critical = (value&0x0ff0) >> 4;
122                         break;
123
124                 case 0x07:
125                         if ((value & 0xf00f) == 0xa000) /* core */
126                                 temps->down_clock = (value&0x0ff0) >> 4;
127                         break;
128
129                 case 0x08:
130                         if ((value & 0xf00f) == 0xa000) /* core */
131                                 temps->fan_boost = (value&0x0ff0) >> 4;
132                         break;
133
134                 case 0x10:
135                         sensor->offset_mult = value;
136                         break;
137
138                 case 0x11:
139                         sensor->offset_div = value;
140                         break;
141
142                 case 0x12:
143                         sensor->slope_mult = value;
144                         break;
145
146                 case 0x13:
147                         sensor->slope_div = value;
148                         break;
149                 }
150                 temp += recordlen;
151         }
152
153         nouveau_temp_safety_checks(dev);
154 }
155
156 static s16
157 nouveau_nv40_sensor_setup(struct drm_device *dev)
158 {
159         struct drm_nouveau_private *dev_priv = dev->dev_private;
160         struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
161         struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
162         u32 offset = sensor->offset_mult / sensor->offset_div;
163         u32 sensor_calibration;
164
165         /* set up the sensors */
166         sensor_calibration = 120 - offset - sensor->offset_constant;
167         sensor_calibration = sensor_calibration * sensor->slope_div /
168                                 sensor->slope_mult;
169
170         if (dev_priv->chipset >= 0x46)
171                 sensor_calibration |= 0x80000000;
172         else
173                 sensor_calibration |= 0x10000000;
174
175         nv_wr32(dev, 0x0015b0, sensor_calibration);
176
177         /* Wait for the sensor to update */
178         msleep(5);
179
180         /* read */
181         return nv_rd32(dev, 0x0015b4);
182 }
183
184 s16
185 nouveau_temp_get(struct drm_device *dev)
186 {
187         struct drm_nouveau_private *dev_priv = dev->dev_private;
188         struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
189         struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
190
191         if (dev_priv->chipset >= 0x84) {
192                 return nv_rd32(dev, 0x20400);
193         } else if (dev_priv->chipset >= 0x40) {
194                 u32 offset = sensor->offset_mult / sensor->offset_div;
195                 u32 core_temp;
196
197                 if (dev_priv->chipset >= 0x50) {
198                         core_temp = nv_rd32(dev, 0x20008);
199                 } else {
200                         core_temp = nv_rd32(dev, 0x0015b4);
201                         /* Setup the sensor if the temperature is 0 */
202                         if (core_temp == 0)
203                                 core_temp = nouveau_nv40_sensor_setup(dev);
204                 }
205
206                 core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
207                 core_temp = core_temp + offset + sensor->offset_constant;
208
209                 return core_temp;
210         } else {
211                 NV_ERROR(dev,
212                                  "Temperature cannot be retrieved from an nv%x card\n",
213                                  dev_priv->chipset);
214                 return 0;
215         }
216
217         return 0;
218 }
219
220 void
221 nouveau_temp_safety_checks(struct drm_device *dev)
222 {
223         struct drm_nouveau_private *dev_priv = dev->dev_private;
224         struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
225         struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
226
227         if (temps->critical > 120)
228                 temps->critical = 120;
229         else if (temps->critical < 80)
230                 temps->critical = 80;
231
232         if (temps->down_clock > 110)
233                 temps->down_clock = 110;
234         else if (temps->down_clock < 60)
235                 temps->down_clock = 60;
236
237         if (temps->fan_boost > 100)
238                 temps->fan_boost = 100;
239         else if (temps->fan_boost < 40)
240                 temps->fan_boost = 40;
241 }
242
243 void
244 nouveau_temp_init(struct drm_device *dev)
245 {
246         struct drm_nouveau_private *dev_priv = dev->dev_private;
247         struct nvbios *bios = &dev_priv->vbios;
248         struct bit_entry P;
249         u8 *temp = NULL;
250
251         if (bios->type == NVBIOS_BIT) {
252                 if (bit_table(dev, 'P', &P))
253                         return;
254
255                 if (P.version == 1)
256                         temp = ROMPTR(bios, P.data[12]);
257                 else if (P.version == 2)
258                         temp = ROMPTR(bios, P.data[16]);
259                 else
260                         NV_WARN(dev, "unknown temp for BIT P %d\n", P.version);
261         } else {
262                 NV_WARN(dev, "BMP entry unknown for temperature table.\n");
263         }
264
265         nouveau_temp_vbios_parse(dev, temp);
266 }
267
268 void
269 nouveau_temp_fini(struct drm_device *dev)
270 {
271
272 }