Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/gpu/drm/nouveau/nouveau_temp.c
15112 views
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
static 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
case 0x4a:
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:
116
if ((value & 0x8f) == 0)
117
sensor->offset_constant = (value >> 9) & 0x7f;
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
157
static int
158
nv40_sensor_setup(struct drm_device *dev)
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 */
182
return nv_rd32(dev, 0x0015b4) & 0x1fff;
183
}
184
185
int
186
nv40_temp_get(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
int offset = sensor->offset_mult / sensor->offset_div;
192
int core_temp;
193
194
if (dev_priv->card_type >= NV_50) {
195
core_temp = nv_rd32(dev, 0x20008);
196
} else {
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);
201
}
202
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);
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
238
static bool
239
probe_monitoring_device(struct nouveau_i2c_chan *i2c,
240
struct i2c_board_info *info)
241
{
242
struct i2c_client *client;
243
244
request_module("%s%s", I2C_MODULE_PREFIX, info->type);
245
246
client = i2c_new_device(&i2c->adapter, info);
247
if (!client)
248
return false;
249
250
if (!client->driver || client->driver->detect(client, info)) {
251
i2c_unregister_device(client);
252
return false;
253
}
254
255
return true;
256
}
257
258
static void
259
nouveau_temp_probe_i2c(struct drm_device *dev)
260
{
261
struct drm_nouveau_private *dev_priv = dev->dev_private;
262
struct dcb_table *dcb = &dev_priv->vbios.dcb;
263
struct i2c_board_info info[] = {
264
{ I2C_BOARD_INFO("w83l785ts", 0x2d) },
265
{ I2C_BOARD_INFO("w83781d", 0x2d) },
266
{ I2C_BOARD_INFO("adt7473", 0x2e) },
267
{ I2C_BOARD_INFO("f75375", 0x2e) },
268
{ I2C_BOARD_INFO("lm99", 0x4c) },
269
{ }
270
};
271
int idx = (dcb->version >= 0x40 ?
272
dcb->i2c_default_indices & 0xf : 2);
273
274
nouveau_i2c_identify(dev, "monitoring device", info,
275
probe_monitoring_device, idx);
276
}
277
278
void
279
nouveau_temp_init(struct drm_device *dev)
280
{
281
struct drm_nouveau_private *dev_priv = dev->dev_private;
282
struct nvbios *bios = &dev_priv->vbios;
283
struct bit_entry P;
284
u8 *temp = NULL;
285
286
if (bios->type == NVBIOS_BIT) {
287
if (bit_table(dev, 'P', &P))
288
return;
289
290
if (P.version == 1)
291
temp = ROMPTR(bios, P.data[12]);
292
else if (P.version == 2)
293
temp = ROMPTR(bios, P.data[16]);
294
else
295
NV_WARN(dev, "unknown temp for BIT P %d\n", P.version);
296
297
nouveau_temp_vbios_parse(dev, temp);
298
}
299
300
nouveau_temp_probe_i2c(dev);
301
}
302
303
void
304
nouveau_temp_fini(struct drm_device *dev)
305
{
306
307
}
308
309