aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/Makefile1
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h46
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/therm.c177
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.c5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_temp.c257
6 files changed, 282 insertions, 205 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index 1c506c5a9a48..b6a6fa7fbcd4 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -35,6 +35,7 @@ nouveau-y += core/subdev/bios/i2c.o
35nouveau-y += core/subdev/bios/init.o 35nouveau-y += core/subdev/bios/init.o
36nouveau-y += core/subdev/bios/mxm.o 36nouveau-y += core/subdev/bios/mxm.o
37nouveau-y += core/subdev/bios/pll.o 37nouveau-y += core/subdev/bios/pll.o
38nouveau-y += core/subdev/bios/therm.o
38nouveau-y += core/subdev/clock/nv04.o 39nouveau-y += core/subdev/clock/nv04.o
39nouveau-y += core/subdev/clock/nv40.o 40nouveau-y += core/subdev/clock/nv40.o
40nouveau-y += core/subdev/clock/nv50.o 41nouveau-y += core/subdev/clock/nv50.o
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h
new file mode 100644
index 000000000000..a2c4296fc5f6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h
@@ -0,0 +1,46 @@
1#ifndef __NVBIOS_THERM_H__
2#define __NVBIOS_THERM_H__
3
4struct nouveau_bios;
5
6struct nvbios_therm_threshold {
7 u8 temp;
8 u8 hysteresis;
9};
10
11struct nvbios_therm_sensor {
12 /* diode */
13 s16 slope_mult;
14 s16 slope_div;
15 s16 offset_num;
16 s16 offset_den;
17 s8 offset_constant;
18
19 /* thresholds */
20 struct nvbios_therm_threshold thrs_fan_boost;
21 struct nvbios_therm_threshold thrs_down_clock;
22 struct nvbios_therm_threshold thrs_critical;
23 struct nvbios_therm_threshold thrs_shutdown;
24};
25
26struct nvbios_therm_fan {
27 u16 pwm_freq;
28
29 u8 min_duty;
30 u8 max_duty;
31};
32
33enum nvbios_therm_domain {
34 NVBIOS_THERM_DOMAIN_CORE,
35 NVBIOS_THERM_DOMAIN_AMBIENT,
36};
37
38int
39nvbios_therm_sensor_parse(struct nouveau_bios *, enum nvbios_therm_domain,
40 struct nvbios_therm_sensor *);
41
42int
43nvbios_therm_fan_parse(struct nouveau_bios *, struct nvbios_therm_fan *);
44
45
46#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c b/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c
new file mode 100644
index 000000000000..862a08a2ae27
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c
@@ -0,0 +1,177 @@
1/*
2 * Copyright 2012 Nouveau Community
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 <subdev/bios.h>
26#include <subdev/bios/bit.h>
27#include <subdev/bios/therm.h>
28
29static u16
30therm_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt)
31{
32 struct bit_entry bit_P;
33 u16 therm = 0;
34
35 if (!bit_entry(bios, 'P', &bit_P)) {
36 if (bit_P.version == 1)
37 therm = nv_ro16(bios, bit_P.offset + 12);
38 else if (bit_P.version == 2)
39 therm = nv_ro16(bios, bit_P.offset + 16);
40 else
41 nv_error(bios,
42 "unknown offset for thermal in BIT P %d\n",
43 bit_P.version);
44 }
45
46 /* exit now if we haven't found the thermal table */
47 if (!therm)
48 return 0x0000;
49
50 *ver = nv_ro08(bios, therm + 0);
51 *hdr = nv_ro08(bios, therm + 1);
52 *len = nv_ro08(bios, therm + 2);
53 *cnt = nv_ro08(bios, therm + 3);
54
55 return therm + nv_ro08(bios, therm + 1);
56}
57
58u16
59nvbios_therm_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
60{
61 u8 hdr, cnt;
62 u16 therm = therm_table(bios, ver, &hdr, len, &cnt);
63 if (therm && idx < cnt)
64 return therm + idx * *len;
65 return 0x0000;
66}
67
68int
69nvbios_therm_sensor_parse(struct nouveau_bios *bios,
70 enum nvbios_therm_domain domain,
71 struct nvbios_therm_sensor *sensor)
72{
73 s8 thrs_section, sensor_section, offset;
74 u8 ver, len, i;
75 u16 entry;
76
77 /* we only support the core domain for now */
78 if (domain != NVBIOS_THERM_DOMAIN_CORE)
79 return -EINVAL;
80
81 /* Read the entries from the table */
82 thrs_section = 0;
83 sensor_section = -1;
84 i = 0;
85 while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) {
86 s16 value = nv_ro16(bios, entry + 1);
87
88 switch (nv_ro08(bios, entry + 0)) {
89 case 0x0:
90 thrs_section = value;
91 if (value > 0)
92 return 0; /* we do not try to support ambient */
93 break;
94 case 0x01:
95 sensor_section++;
96 if (sensor_section == 0) {
97 offset = ((s8) nv_ro08(bios, entry + 2)) / 2;
98 sensor->offset_constant = offset;
99 }
100 break;
101
102 case 0x04:
103 if (thrs_section == 0) {
104 sensor->thrs_critical.temp = (value & 0xff0) >> 4;
105 sensor->thrs_critical.hysteresis = value & 0xf;
106 }
107 break;
108
109 case 0x07:
110 if (thrs_section == 0) {
111 sensor->thrs_down_clock.temp = (value & 0xff0) >> 4;
112 sensor->thrs_down_clock.hysteresis = value & 0xf;
113 }
114 break;
115
116 case 0x08:
117 if (thrs_section == 0) {
118 sensor->thrs_fan_boost.temp = (value & 0xff0) >> 4;
119 sensor->thrs_fan_boost.hysteresis = value & 0xf;
120 }
121 break;
122
123 case 0x10:
124 if (sensor_section == 0)
125 sensor->offset_num = value;
126 break;
127
128 case 0x11:
129 if (sensor_section == 0)
130 sensor->offset_den = value;
131 break;
132
133 case 0x12:
134 if (sensor_section == 0)
135 sensor->slope_mult = value;
136 break;
137
138 case 0x13:
139 if (sensor_section == 0)
140 sensor->slope_div = value;
141 break;
142 case 0x32:
143 if (thrs_section == 0) {
144 sensor->thrs_shutdown.temp = (value & 0xff0) >> 4;
145 sensor->thrs_shutdown.hysteresis = value & 0xf;
146 }
147 break;
148 }
149 }
150
151 return 0;
152}
153
154int
155nvbios_therm_fan_parse(struct nouveau_bios *bios,
156 struct nvbios_therm_fan *fan)
157{
158 u8 ver, len, i;
159 u16 entry;
160
161 i = 0;
162 while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) {
163 s16 value = nv_ro16(bios, entry + 1);
164
165 switch (nv_ro08(bios, entry + 0)) {
166 case 0x22:
167 fan->min_duty = value & 0xff;
168 fan->max_duty = (value & 0xff00) >> 8;
169 break;
170 case 0x26:
171 fan->pwm_freq = value;
172 break;
173 }
174 }
175
176 return 0;
177}
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index d2f2de67f688..bdd50953488c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -891,10 +891,7 @@ nouveau_pm_init(struct drm_device *dev)
891 } 891 }
892 pm->voltage_get = nouveau_voltage_gpio_get; 892 pm->voltage_get = nouveau_voltage_gpio_get;
893 pm->voltage_set = nouveau_voltage_gpio_set; 893 pm->voltage_set = nouveau_voltage_gpio_set;
894 if (device->chipset == 0x50) 894 pm->temp_get = nv84_temp_get;
895 pm->temp_get = nv40_temp_get;
896 else
897 pm->temp_get = nv84_temp_get;
898 pm->pwm_get = nv50_pm_pwm_get; 895 pm->pwm_get = nv50_pm_pwm_get;
899 pm->pwm_set = nv50_pm_pwm_set; 896 pm->pwm_set = nv50_pm_pwm_set;
900 } else 897 } else
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h
index e2ec9c0ed567..2e39ccbd5d46 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.h
@@ -148,7 +148,6 @@ struct nouveau_pm_temp_sensor_constants {
148struct nouveau_pm_threshold_temp { 148struct nouveau_pm_threshold_temp {
149 s16 critical; 149 s16 critical;
150 s16 down_clock; 150 s16 down_clock;
151 s16 fan_boost;
152}; 151};
153 152
154struct nouveau_pm_fan { 153struct nouveau_pm_fan {
diff --git a/drivers/gpu/drm/nouveau/nouveau_temp.c b/drivers/gpu/drm/nouveau/nouveau_temp.c
index 7ae25e47be9f..5465abf87f18 100644
--- a/drivers/gpu/drm/nouveau/nouveau_temp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_temp.c
@@ -30,187 +30,23 @@
30#include "nouveau_pm.h" 30#include "nouveau_pm.h"
31 31
32#include <subdev/i2c.h> 32#include <subdev/i2c.h>
33 33#include <subdev/bios/therm.h>
34static void
35nouveau_temp_vbios_parse(struct drm_device *dev, u8 *temp)
36{
37 struct nouveau_drm *drm = nouveau_drm(dev);
38 struct nouveau_pm *pm = nouveau_pm(dev);
39 struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
40 struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
41 int i, headerlen, recordlen, entries;
42
43 if (!temp) {
44 NV_DEBUG(drm, "temperature table pointer invalid\n");
45 return;
46 }
47
48 /* Set the default sensor's contants */
49 sensor->offset_constant = 0;
50 sensor->offset_mult = 0;
51 sensor->offset_div = 1;
52 sensor->slope_mult = 1;
53 sensor->slope_div = 1;
54
55 /* Set the default temperature thresholds */
56 temps->critical = 110;
57 temps->down_clock = 100;
58 temps->fan_boost = 90;
59
60 /* Set the default range for the pwm fan */
61 pm->fan.min_duty = 30;
62 pm->fan.max_duty = 100;
63
64 /* Set the known default values to setup the temperature sensor */
65 if (nv_device(drm->device)->card_type >= NV_40) {
66 switch (nv_device(drm->device)->chipset) {
67 case 0x43:
68 sensor->offset_mult = 32060;
69 sensor->offset_div = 1000;
70 sensor->slope_mult = 792;
71 sensor->slope_div = 1000;
72 break;
73
74 case 0x44:
75 case 0x47:
76 case 0x4a:
77 sensor->offset_mult = 27839;
78 sensor->offset_div = 1000;
79 sensor->slope_mult = 780;
80 sensor->slope_div = 1000;
81 break;
82
83 case 0x46:
84 sensor->offset_mult = -24775;
85 sensor->offset_div = 100;
86 sensor->slope_mult = 467;
87 sensor->slope_div = 10000;
88 break;
89
90 case 0x49:
91 sensor->offset_mult = -25051;
92 sensor->offset_div = 100;
93 sensor->slope_mult = 458;
94 sensor->slope_div = 10000;
95 break;
96
97 case 0x4b:
98 sensor->offset_mult = -24088;
99 sensor->offset_div = 100;
100 sensor->slope_mult = 442;
101 sensor->slope_div = 10000;
102 break;
103
104 case 0x50:
105 sensor->offset_mult = -22749;
106 sensor->offset_div = 100;
107 sensor->slope_mult = 431;
108 sensor->slope_div = 10000;
109 break;
110
111 case 0x67:
112 sensor->offset_mult = -26149;
113 sensor->offset_div = 100;
114 sensor->slope_mult = 484;
115 sensor->slope_div = 10000;
116 break;
117 }
118 }
119
120 headerlen = temp[1];
121 recordlen = temp[2];
122 entries = temp[3];
123 temp = temp + headerlen;
124
125 /* Read the entries from the table */
126 for (i = 0; i < entries; i++) {
127 s16 value = ROM16(temp[1]);
128
129 switch (temp[0]) {
130 case 0x01:
131 if ((value & 0x8f) == 0)
132 sensor->offset_constant = (value >> 9) & 0x7f;
133 break;
134
135 case 0x04:
136 if ((value & 0xf00f) == 0xa000) /* core */
137 temps->critical = (value&0x0ff0) >> 4;
138 break;
139
140 case 0x07:
141 if ((value & 0xf00f) == 0xa000) /* core */
142 temps->down_clock = (value&0x0ff0) >> 4;
143 break;
144
145 case 0x08:
146 if ((value & 0xf00f) == 0xa000) /* core */
147 temps->fan_boost = (value&0x0ff0) >> 4;
148 break;
149
150 case 0x10:
151 sensor->offset_mult = value;
152 break;
153
154 case 0x11:
155 sensor->offset_div = value;
156 break;
157
158 case 0x12:
159 sensor->slope_mult = value;
160 break;
161
162 case 0x13:
163 sensor->slope_div = value;
164 break;
165 case 0x22:
166 pm->fan.min_duty = value & 0xff;
167 pm->fan.max_duty = (value & 0xff00) >> 8;
168 break;
169 case 0x26:
170 pm->fan.pwm_freq = value;
171 break;
172 }
173 temp += recordlen;
174 }
175
176 nouveau_temp_safety_checks(dev);
177
178 /* check the fan min/max settings */
179 if (pm->fan.min_duty < 10)
180 pm->fan.min_duty = 10;
181 if (pm->fan.max_duty > 100)
182 pm->fan.max_duty = 100;
183 if (pm->fan.max_duty < pm->fan.min_duty)
184 pm->fan.max_duty = pm->fan.min_duty;
185}
186 34
187static int 35static int
188nv40_sensor_setup(struct drm_device *dev) 36nv40_sensor_setup(struct drm_device *dev)
189{ 37{
190 struct nouveau_device *device = nouveau_dev(dev); 38 struct nouveau_device *device = nouveau_dev(dev);
191 struct nouveau_drm *drm = nouveau_drm(dev); 39 struct nouveau_drm *drm = nouveau_drm(dev);
192 struct nouveau_pm *pm = nouveau_pm(dev);
193 struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
194 s32 offset = sensor->offset_mult / sensor->offset_div;
195 s32 sensor_calibration;
196
197 /* set up the sensors */
198 sensor_calibration = 120 - offset - sensor->offset_constant;
199 sensor_calibration = sensor_calibration * sensor->slope_div /
200 sensor->slope_mult;
201 40
202 if (nv_device(drm->device)->chipset >= 0x46) 41 /* enable ADC readout and disable the ALARM threshold */
203 sensor_calibration |= 0x80000000; 42 if (nv_device(drm->device)->chipset >= 0x46) {
204 else 43 nv_mask(device, 0x15b8, 0x80000000, 0);
205 sensor_calibration |= 0x10000000; 44 nv_wr32(device, 0x15b0, 0x80003fff);
206 45 return nv_rd32(device, 0x15b4) & 0x3fff;
207 nv_wr32(device, 0x0015b0, sensor_calibration); 46 } else {
208 47 nv_wr32(device, 0x15b0, 0xff);
209 /* Wait for the sensor to update */ 48 return nv_rd32(device, 0x15b4) & 0xff;
210 msleep(5); 49 }
211
212 /* read */
213 return nv_rd32(device, 0x0015b4) & 0x1fff;
214} 50}
215 51
216int 52int
@@ -220,20 +56,30 @@ nv40_temp_get(struct drm_device *dev)
220 struct nouveau_drm *drm = nouveau_drm(dev); 56 struct nouveau_drm *drm = nouveau_drm(dev);
221 struct nouveau_pm *pm = nouveau_pm(dev); 57 struct nouveau_pm *pm = nouveau_pm(dev);
222 struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants; 58 struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
223 int offset = sensor->offset_mult / sensor->offset_div;
224 int core_temp; 59 int core_temp;
225 60
226 if (nv_device(drm->device)->card_type >= NV_50) { 61 if (nv_device(drm->device)->chipset >= 0x46) {
227 core_temp = nv_rd32(device, 0x20008); 62 nv_wr32(device, 0x15b0, 0x80003fff);
63 core_temp = nv_rd32(device, 0x15b4) & 0x3fff;
228 } else { 64 } else {
229 core_temp = nv_rd32(device, 0x0015b4) & 0x1fff; 65 nv_wr32(device, 0x15b0, 0xff);
230 /* Setup the sensor if the temperature is 0 */ 66 core_temp = nv_rd32(device, 0x15b4) & 0xff;
231 if (core_temp == 0)
232 core_temp = nv40_sensor_setup(dev);
233 } 67 }
234 68
69 /* Setup the sensor if the temperature is 0 */
70 if (core_temp == 0)
71 core_temp = nv40_sensor_setup(dev);
72
73 if (sensor->slope_div == 0)
74 sensor->slope_div = 1;
75 if (sensor->offset_div == 0)
76 sensor->offset_div = 1;
77 if (sensor->slope_mult < 1)
78 sensor->slope_mult = 1;
79
235 core_temp = core_temp * sensor->slope_mult / sensor->slope_div; 80 core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
236 core_temp = core_temp + offset + sensor->offset_constant; 81 core_temp = core_temp + sensor->offset_mult / sensor->offset_div;
82 core_temp = core_temp + sensor->offset_constant - 8;
237 83
238 return core_temp; 84 return core_temp;
239} 85}
@@ -260,11 +106,6 @@ nouveau_temp_safety_checks(struct drm_device *dev)
260 temps->down_clock = 110; 106 temps->down_clock = 110;
261 else if (temps->down_clock < 60) 107 else if (temps->down_clock < 60)
262 temps->down_clock = 60; 108 temps->down_clock = 60;
263
264 if (temps->fan_boost > 100)
265 temps->fan_boost = 100;
266 else if (temps->fan_boost < 40)
267 temps->fan_boost = 40;
268} 109}
269 110
270static bool 111static bool
@@ -309,24 +150,40 @@ void
309nouveau_temp_init(struct drm_device *dev) 150nouveau_temp_init(struct drm_device *dev)
310{ 151{
311 struct nouveau_drm *drm = nouveau_drm(dev); 152 struct nouveau_drm *drm = nouveau_drm(dev);
312 struct nvbios *bios = &drm->vbios; 153 struct nouveau_device *device = nv_device(drm->device);
313 struct bit_entry P; 154 struct nouveau_bios *bios = nouveau_bios(device);
314 u8 *temp = NULL; 155 struct nouveau_pm *pm = nouveau_pm(dev);
156 struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
157 struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
158 struct nvbios_therm_sensor bios_sensor;
159 struct nvbios_therm_fan bios_fan;
315 160
316 if (bios->type == NVBIOS_BIT) { 161 /* store some safe defaults */
317 if (bit_table(dev, 'P', &P)) 162 sensor->offset_constant = 0;
318 return; 163 sensor->offset_mult = 0;
164 sensor->offset_div = 1;
165 sensor->slope_mult = 1;
166 sensor->slope_div = 1;
319 167
320 if (P.version == 1) 168 if (!nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE,
321 temp = ROMPTR(dev, P.data[12]); 169 &bios_sensor)) {
322 else if (P.version == 2) 170 sensor->slope_mult = bios_sensor.slope_mult;
323 temp = ROMPTR(dev, P.data[16]); 171 sensor->slope_div = bios_sensor.slope_div;
324 else 172 sensor->offset_mult = bios_sensor.offset_num;
325 NV_WARN(drm, "unknown temp for BIT P %d\n", P.version); 173 sensor->offset_div = bios_sensor.offset_den;
174 sensor->offset_constant = bios_sensor.offset_constant;
326 175
327 nouveau_temp_vbios_parse(dev, temp); 176 temps->down_clock = bios_sensor.thrs_down_clock.temp;
177 temps->critical = bios_sensor.thrs_critical.temp;
328 } 178 }
329 179
180 if (nvbios_therm_fan_parse(bios, &bios_fan)) {
181 pm->fan.min_duty = bios_fan.min_duty;
182 pm->fan.max_duty = bios_fan.max_duty;
183 pm->fan.pwm_freq = bios_fan.pwm_freq;
184 }
185
186 nouveau_temp_safety_checks(dev);
330 nouveau_temp_probe_i2c(dev); 187 nouveau_temp_probe_i2c(dev);
331} 188}
332 189