blob: 5a46446dd5a8682e4773b8a0ff60724ef7de3514 [file] [log] [blame]
Martin Peres34e9d852010-09-22 20:54:22 +02001/*
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
Paul Gortmakere0cd3602011-08-30 11:04:30 -040025#include <linux/module.h>
26
Martin Peres34e9d852010-09-22 20:54:22 +020027#include "drmP.h"
28
29#include "nouveau_drv.h"
30#include "nouveau_pm.h"
31
Francisco Jerez5c4abd02010-09-23 20:36:42 +020032static void
Martin Peres34e9d852010-09-22 20:54:22 +020033nouveau_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;
Emil Velikov40ce4272011-06-22 02:13:23 +010048 sensor->offset_mult = 0;
Martin Peres34e9d852010-09-22 20:54:22 +020049 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 known default values to setup the temperature sensor */
59 if (dev_priv->card_type >= NV_40) {
60 switch (dev_priv->chipset) {
61 case 0x43:
62 sensor->offset_mult = 32060;
63 sensor->offset_div = 1000;
64 sensor->slope_mult = 792;
65 sensor->slope_div = 1000;
66 break;
67
68 case 0x44:
69 case 0x47:
Francisco Jerezd34ec502010-09-23 16:27:14 +020070 case 0x4a:
Martin Peres34e9d852010-09-22 20:54:22 +020071 sensor->offset_mult = 27839;
72 sensor->offset_div = 1000;
73 sensor->slope_mult = 780;
74 sensor->slope_div = 1000;
75 break;
76
77 case 0x46:
78 sensor->offset_mult = -24775;
79 sensor->offset_div = 100;
80 sensor->slope_mult = 467;
81 sensor->slope_div = 10000;
82 break;
83
84 case 0x49:
85 sensor->offset_mult = -25051;
86 sensor->offset_div = 100;
87 sensor->slope_mult = 458;
88 sensor->slope_div = 10000;
89 break;
90
91 case 0x4b:
92 sensor->offset_mult = -24088;
93 sensor->offset_div = 100;
94 sensor->slope_mult = 442;
95 sensor->slope_div = 10000;
96 break;
97
98 case 0x50:
99 sensor->offset_mult = -22749;
100 sensor->offset_div = 100;
101 sensor->slope_mult = 431;
102 sensor->slope_div = 10000;
103 break;
Emil Velikov6d13e9c2011-06-22 02:54:39 +0100104
105 case 0x67:
106 sensor->offset_mult = -26149;
107 sensor->offset_div = 100;
108 sensor->slope_mult = 484;
109 sensor->slope_div = 10000;
110 break;
Martin Peres34e9d852010-09-22 20:54:22 +0200111 }
112 }
113
114 headerlen = temp[1];
115 recordlen = temp[2];
116 entries = temp[3];
117 temp = temp + headerlen;
118
119 /* Read the entries from the table */
120 for (i = 0; i < entries; i++) {
Emil Velikov40ce4272011-06-22 02:13:23 +0100121 s16 value = ROM16(temp[1]);
Martin Peres34e9d852010-09-22 20:54:22 +0200122
123 switch (temp[0]) {
124 case 0x01:
Francisco Jerez67e1d4f2010-09-23 17:01:05 +0200125 if ((value & 0x8f) == 0)
126 sensor->offset_constant = (value >> 9) & 0x7f;
Martin Peres34e9d852010-09-22 20:54:22 +0200127 break;
128
129 case 0x04:
130 if ((value & 0xf00f) == 0xa000) /* core */
131 temps->critical = (value&0x0ff0) >> 4;
132 break;
133
134 case 0x07:
135 if ((value & 0xf00f) == 0xa000) /* core */
136 temps->down_clock = (value&0x0ff0) >> 4;
137 break;
138
139 case 0x08:
140 if ((value & 0xf00f) == 0xa000) /* core */
141 temps->fan_boost = (value&0x0ff0) >> 4;
142 break;
143
144 case 0x10:
145 sensor->offset_mult = value;
146 break;
147
148 case 0x11:
149 sensor->offset_div = value;
150 break;
151
152 case 0x12:
153 sensor->slope_mult = value;
154 break;
155
156 case 0x13:
157 sensor->slope_div = value;
158 break;
159 }
160 temp += recordlen;
161 }
162
163 nouveau_temp_safety_checks(dev);
164}
165
Francisco Jerez8155cac2010-09-23 20:58:38 +0200166static int
167nv40_sensor_setup(struct drm_device *dev)
Martin Peres34e9d852010-09-22 20:54:22 +0200168{
169 struct drm_nouveau_private *dev_priv = dev->dev_private;
170 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
171 struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
Emil Velikov40ce4272011-06-22 02:13:23 +0100172 s32 offset = sensor->offset_mult / sensor->offset_div;
173 s32 sensor_calibration;
Martin Peres34e9d852010-09-22 20:54:22 +0200174
175 /* set up the sensors */
176 sensor_calibration = 120 - offset - sensor->offset_constant;
177 sensor_calibration = sensor_calibration * sensor->slope_div /
178 sensor->slope_mult;
179
180 if (dev_priv->chipset >= 0x46)
181 sensor_calibration |= 0x80000000;
182 else
183 sensor_calibration |= 0x10000000;
184
185 nv_wr32(dev, 0x0015b0, sensor_calibration);
186
187 /* Wait for the sensor to update */
188 msleep(5);
189
190 /* read */
Francesco Marella41647432010-09-23 09:14:22 +0200191 return nv_rd32(dev, 0x0015b4) & 0x1fff;
Martin Peres34e9d852010-09-22 20:54:22 +0200192}
193
Francisco Jerez8155cac2010-09-23 20:58:38 +0200194int
195nv40_temp_get(struct drm_device *dev)
Martin Peres34e9d852010-09-22 20:54:22 +0200196{
197 struct drm_nouveau_private *dev_priv = dev->dev_private;
198 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
199 struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
Francisco Jerez8155cac2010-09-23 20:58:38 +0200200 int offset = sensor->offset_mult / sensor->offset_div;
201 int core_temp;
Martin Peres34e9d852010-09-22 20:54:22 +0200202
Francisco Jerezc1b60ec2010-11-11 00:56:37 +0100203 if (dev_priv->card_type >= NV_50) {
Francisco Jerez8155cac2010-09-23 20:58:38 +0200204 core_temp = nv_rd32(dev, 0x20008);
Martin Peres34e9d852010-09-22 20:54:22 +0200205 } else {
Francisco Jerez8155cac2010-09-23 20:58:38 +0200206 core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff;
207 /* Setup the sensor if the temperature is 0 */
208 if (core_temp == 0)
209 core_temp = nv40_sensor_setup(dev);
Martin Peres34e9d852010-09-22 20:54:22 +0200210 }
211
Francisco Jerez8155cac2010-09-23 20:58:38 +0200212 core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
213 core_temp = core_temp + offset + sensor->offset_constant;
214
215 return core_temp;
216}
217
218int
219nv84_temp_get(struct drm_device *dev)
220{
221 return nv_rd32(dev, 0x20400);
Martin Peres34e9d852010-09-22 20:54:22 +0200222}
223
224void
225nouveau_temp_safety_checks(struct drm_device *dev)
226{
227 struct drm_nouveau_private *dev_priv = dev->dev_private;
228 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
229 struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
230
231 if (temps->critical > 120)
232 temps->critical = 120;
233 else if (temps->critical < 80)
234 temps->critical = 80;
235
236 if (temps->down_clock > 110)
237 temps->down_clock = 110;
238 else if (temps->down_clock < 60)
239 temps->down_clock = 60;
240
241 if (temps->fan_boost > 100)
242 temps->fan_boost = 100;
243 else if (temps->fan_boost < 40)
244 temps->fan_boost = 40;
245}
246
Francisco Jerez66146da2010-09-23 21:00:40 +0200247static bool
248probe_monitoring_device(struct nouveau_i2c_chan *i2c,
249 struct i2c_board_info *info)
250{
Francisco Jerez66146da2010-09-23 21:00:40 +0200251 struct i2c_client *client;
252
Lucas Stachf17811d2011-02-06 22:42:54 +0100253 request_module("%s%s", I2C_MODULE_PREFIX, info->type);
Francisco Jerez66146da2010-09-23 21:00:40 +0200254
255 client = i2c_new_device(&i2c->adapter, info);
256 if (!client)
257 return false;
258
259 if (!client->driver || client->driver->detect(client, info)) {
260 i2c_unregister_device(client);
261 return false;
262 }
263
264 return true;
265}
266
267static void
268nouveau_temp_probe_i2c(struct drm_device *dev)
269{
270 struct drm_nouveau_private *dev_priv = dev->dev_private;
271 struct dcb_table *dcb = &dev_priv->vbios.dcb;
272 struct i2c_board_info info[] = {
273 { I2C_BOARD_INFO("w83l785ts", 0x2d) },
274 { I2C_BOARD_INFO("w83781d", 0x2d) },
Francisco Jerez66146da2010-09-23 21:00:40 +0200275 { I2C_BOARD_INFO("adt7473", 0x2e) },
Ben Skeggsb26e72f2011-01-19 15:54:10 +1000276 { I2C_BOARD_INFO("f75375", 0x2e) },
Francisco Jerez66146da2010-09-23 21:00:40 +0200277 { I2C_BOARD_INFO("lm99", 0x4c) },
278 { }
279 };
280 int idx = (dcb->version >= 0x40 ?
281 dcb->i2c_default_indices & 0xf : 2);
282
283 nouveau_i2c_identify(dev, "monitoring device", info,
284 probe_monitoring_device, idx);
285}
286
Martin Peres34e9d852010-09-22 20:54:22 +0200287void
288nouveau_temp_init(struct drm_device *dev)
289{
290 struct drm_nouveau_private *dev_priv = dev->dev_private;
291 struct nvbios *bios = &dev_priv->vbios;
292 struct bit_entry P;
293 u8 *temp = NULL;
294
295 if (bios->type == NVBIOS_BIT) {
296 if (bit_table(dev, 'P', &P))
297 return;
298
299 if (P.version == 1)
300 temp = ROMPTR(bios, P.data[12]);
301 else if (P.version == 2)
302 temp = ROMPTR(bios, P.data[16]);
303 else
304 NV_WARN(dev, "unknown temp for BIT P %d\n", P.version);
Francisco Jerez66146da2010-09-23 21:00:40 +0200305
306 nouveau_temp_vbios_parse(dev, temp);
Martin Peres34e9d852010-09-22 20:54:22 +0200307 }
308
Francisco Jerez66146da2010-09-23 21:00:40 +0200309 nouveau_temp_probe_i2c(dev);
Martin Peres34e9d852010-09-22 20:54:22 +0200310}
311
312void
313nouveau_temp_fini(struct drm_device *dev)
314{
315
316}