Commit | Line | Data |
---|---|---|
34e9d85a MP |
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 */ | |
4164743c | 181 | return nv_rd32(dev, 0x0015b4) & 0x1fff; |
34e9d85a MP |
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 { | |
4164743c | 200 | core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff; |
34e9d85a MP |
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 | } |