Set memory attributes on page
[pscnv.git] / pscnv / nouveau_temp.c
blobde761855681cbf1586c300ec062b09a8f54ca184
1 /*
2 * Copyright 2010 PathScale inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
22 * Authors: Martin Peres
25 #ifdef __linux__
26 #include <linux/module.h>
27 #endif
28 #include "nouveau_drv.h"
29 #include "nouveau_pm.h"
31 static void
32 nouveau_temp_vbios_parse(struct drm_device *dev, u8 *temp)
34 struct drm_nouveau_private *dev_priv = dev->dev_private;
35 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
36 struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
37 struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
38 int i, headerlen, recordlen, entries;
40 if (!temp) {
41 NV_DEBUG(dev, "temperature table pointer invalid\n");
42 return;
45 /* Set the default sensor's contants */
46 sensor->offset_constant = 0;
47 sensor->offset_mult = 1;
48 sensor->offset_div = 1;
49 sensor->slope_mult = 1;
50 sensor->slope_div = 1;
52 /* Set the default temperature thresholds */
53 temps->critical = 110;
54 temps->down_clock = 100;
55 temps->fan_boost = 90;
57 /* Set the known default values to setup the temperature sensor */
58 if (dev_priv->card_type >= NV_40) {
59 switch (dev_priv->chipset) {
60 case 0x43:
61 sensor->offset_mult = 32060;
62 sensor->offset_div = 1000;
63 sensor->slope_mult = 792;
64 sensor->slope_div = 1000;
65 break;
67 case 0x44:
68 case 0x47:
69 case 0x4a:
70 sensor->offset_mult = 27839;
71 sensor->offset_div = 1000;
72 sensor->slope_mult = 780;
73 sensor->slope_div = 1000;
74 break;
76 case 0x46:
77 sensor->offset_mult = -24775;
78 sensor->offset_div = 100;
79 sensor->slope_mult = 467;
80 sensor->slope_div = 10000;
81 break;
83 case 0x49:
84 sensor->offset_mult = -25051;
85 sensor->offset_div = 100;
86 sensor->slope_mult = 458;
87 sensor->slope_div = 10000;
88 break;
90 case 0x4b:
91 sensor->offset_mult = -24088;
92 sensor->offset_div = 100;
93 sensor->slope_mult = 442;
94 sensor->slope_div = 10000;
95 break;
97 case 0x50:
98 sensor->offset_mult = -22749;
99 sensor->offset_div = 100;
100 sensor->slope_mult = 431;
101 sensor->slope_div = 10000;
102 break;
106 headerlen = temp[1];
107 recordlen = temp[2];
108 entries = temp[3];
109 temp = temp + headerlen;
111 /* Read the entries from the table */
112 for (i = 0; i < entries; i++) {
113 u16 value = ROM16(temp[1]);
115 switch (temp[0]) {
116 case 0x01:
117 if ((value & 0x8f) == 0)
118 sensor->offset_constant = (value >> 9) & 0x7f;
119 break;
121 case 0x04:
122 if ((value & 0xf00f) == 0xa000) /* core */
123 temps->critical = (value&0x0ff0) >> 4;
124 break;
126 case 0x07:
127 if ((value & 0xf00f) == 0xa000) /* core */
128 temps->down_clock = (value&0x0ff0) >> 4;
129 break;
131 case 0x08:
132 if ((value & 0xf00f) == 0xa000) /* core */
133 temps->fan_boost = (value&0x0ff0) >> 4;
134 break;
136 case 0x10:
137 sensor->offset_mult = value;
138 break;
140 case 0x11:
141 sensor->offset_div = value;
142 break;
144 case 0x12:
145 sensor->slope_mult = value;
146 break;
148 case 0x13:
149 sensor->slope_div = value;
150 break;
151 case 0x22:
152 pm->fan.min_duty = value & 0xff;
153 pm->fan.max_duty = (value & 0xff00) >> 8;
154 break;
155 case 0x26:
156 pm->fan.pwm_freq = value;
157 break;
159 temp += recordlen;
162 nouveau_temp_safety_checks(dev);
164 /* check the fan min/max settings */
165 if (pm->fan.min_duty < 10)
166 pm->fan.min_duty = 10;
167 if (pm->fan.max_duty > 100)
168 pm->fan.max_duty = 100;
169 if (pm->fan.max_duty < pm->fan.min_duty)
170 pm->fan.max_duty = pm->fan.min_duty;
173 static int
174 nv40_sensor_setup(struct drm_device *dev)
176 struct drm_nouveau_private *dev_priv = dev->dev_private;
177 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
178 struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
179 u32 offset = sensor->offset_mult / sensor->offset_div;
180 u32 sensor_calibration;
182 /* set up the sensors */
183 sensor_calibration = 120 - offset - sensor->offset_constant;
184 sensor_calibration = sensor_calibration * sensor->slope_div /
185 sensor->slope_mult;
187 if (dev_priv->chipset >= 0x46)
188 sensor_calibration |= 0x80000000;
189 else
190 sensor_calibration |= 0x10000000;
192 nv_wr32(dev, 0x0015b0, sensor_calibration);
194 /* Wait for the sensor to update */
195 msleep(5);
197 /* read */
198 return nv_rd32(dev, 0x0015b4) & 0x1fff;
202 nv40_temp_get(struct drm_device *dev)
204 struct drm_nouveau_private *dev_priv = dev->dev_private;
205 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
206 struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
207 int offset = sensor->offset_mult / sensor->offset_div;
208 int core_temp;
210 if (dev_priv->chipset >= 0x50) {
211 core_temp = nv_rd32(dev, 0x20008);
212 } else {
213 core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff;
214 /* Setup the sensor if the temperature is 0 */
215 if (core_temp == 0)
216 core_temp = nv40_sensor_setup(dev);
219 core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
220 core_temp = core_temp + offset + sensor->offset_constant;
222 return core_temp;
226 nv84_temp_get(struct drm_device *dev)
228 return nv_rd32(dev, 0x20400);
231 void
232 nouveau_temp_safety_checks(struct drm_device *dev)
234 struct drm_nouveau_private *dev_priv = dev->dev_private;
235 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
236 struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
238 if (temps->critical > 120)
239 temps->critical = 120;
240 else if (temps->critical < 80)
241 temps->critical = 80;
243 if (temps->down_clock > 110)
244 temps->down_clock = 110;
245 else if (temps->down_clock < 60)
246 temps->down_clock = 60;
248 if (temps->fan_boost > 100)
249 temps->fan_boost = 100;
250 else if (temps->fan_boost < 40)
251 temps->fan_boost = 40;
254 static bool
255 probe_monitoring_device(struct nouveau_i2c_chan *i2c,
256 struct i2c_board_info *info)
258 #ifdef __linux__
259 char modalias[16] = "i2c:";
260 struct i2c_client *client;
262 strlcat(modalias, info->type, sizeof(modalias));
263 request_module(modalias);
265 client = i2c_new_device(&i2c->adapter, info);
266 if (!client)
267 return false;
269 if (!client->driver || client->driver->detect(client, info)) {
270 i2c_unregister_device(client);
271 return false;
273 #else
274 NV_WARN(i2c->dev, "Can not test for monitoring device \"%s\" on %02x due to missing os support\n", info->name, info->addr);
275 #endif
277 return true;
280 static void
281 nouveau_temp_probe_i2c(struct drm_device *dev)
283 struct drm_nouveau_private *dev_priv = dev->dev_private;
284 struct dcb_table *dcb = &dev_priv->vbios.dcb;
285 struct i2c_board_info info[] = {
286 { I2C_BOARD_INFO("w83l785ts", 0x2d) },
287 { I2C_BOARD_INFO("w83781d", 0x2d) },
288 { I2C_BOARD_INFO("f75375", 0x2e) },
289 { I2C_BOARD_INFO("adt7473", 0x2e) },
290 { I2C_BOARD_INFO("lm99", 0x4c) },
293 int idx = (dcb->version >= 0x40 ?
294 dcb->i2c_default_indices & 0xf : 2);
296 nouveau_i2c_identify(dev, "monitoring device", info,
297 probe_monitoring_device, idx);
300 void
301 nouveau_temp_init(struct drm_device *dev)
303 struct drm_nouveau_private *dev_priv = dev->dev_private;
304 struct nvbios *bios = &dev_priv->vbios;
305 struct bit_entry P;
306 u8 *temp = NULL;
308 if (bios->type == NVBIOS_BIT) {
309 if (bit_table(dev, 'P', &P))
310 return;
312 if (P.version == 1)
313 temp = ROMPTR(bios, P.data[12]);
314 else if (P.version == 2)
315 temp = ROMPTR(bios, P.data[16]);
316 else
317 NV_WARN(dev, "unknown temp for BIT P %d\n", P.version);
319 nouveau_temp_vbios_parse(dev, temp);
322 nouveau_temp_probe_i2c(dev);
325 void
326 nouveau_temp_fini(struct drm_device *dev)