aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_temp.c
diff options
context:
space:
mode:
authorMartin Peres <martin.peres@labri.fr>2012-09-01 20:55:58 -0400
committerBen Skeggs <bskeggs@redhat.com>2012-10-02 23:13:14 -0400
commitaa1b9b4836a8ab093ec06b0780553566a5430da7 (patch)
tree26c305c62178ad4f9bf9644b6b7766cb0af87b1f /drivers/gpu/drm/nouveau/nouveau_temp.c
parentd46497dce7376e9d3e2e10c59d92e1c3b665b5dd (diff)
drm/nouveau/therm: move thermal-related functions to the therm subdev
It looks scary because of the size, but I tried to keep the differences minimal. Further patches will fix the actual "driver" code and add new features. v2: change filenames, split to submodules v3: add a missing include v4: Ben Skeggs <bskeggs@redhat.com> - fixed set_defaults() to allow min_duty < 30 (thermal table will override this if it's actually necessary) - fixed set_defaults() to not provide pwm_freq so nv4x (which only has pwm_div) can actually work. the boards using pwm_freq will have a thermal table entry to provide us the value. - removed unused files Signed-off-by: Martin Peres <martin.peres@labri.fr> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_temp.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_temp.c237
1 files changed, 0 insertions, 237 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_temp.c b/drivers/gpu/drm/nouveau/nouveau_temp.c
deleted file mode 100644
index 6d2b957ca016..000000000000
--- a/drivers/gpu/drm/nouveau/nouveau_temp.c
+++ /dev/null
@@ -1,237 +0,0 @@
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 <linux/module.h>
26
27#include "drmP.h"
28
29#include "nouveau_drm.h"
30#include "nouveau_pm.h"
31
32#include <subdev/i2c.h>
33#include <subdev/bios/therm.h>
34#include <subdev/bios/extdev.h>
35
36static int
37nv40_sensor_setup(struct drm_device *dev)
38{
39 struct nouveau_device *device = nouveau_dev(dev);
40 struct nouveau_drm *drm = nouveau_drm(dev);
41
42 /* enable ADC readout and disable the ALARM threshold */
43 if (nv_device(drm->device)->chipset >= 0x46) {
44 nv_mask(device, 0x15b8, 0x80000000, 0);
45 nv_wr32(device, 0x15b0, 0x80003fff);
46 return nv_rd32(device, 0x15b4) & 0x3fff;
47 } else {
48 nv_wr32(device, 0x15b0, 0xff);
49 return nv_rd32(device, 0x15b4) & 0xff;
50 }
51}
52
53int
54nv40_temp_get(struct drm_device *dev)
55{
56 struct nouveau_device *device = nouveau_dev(dev);
57 struct nouveau_drm *drm = nouveau_drm(dev);
58 struct nouveau_pm *pm = nouveau_pm(dev);
59 struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
60 int core_temp;
61
62 if (nv_device(drm->device)->chipset >= 0x46) {
63 nv_wr32(device, 0x15b0, 0x80003fff);
64 core_temp = nv_rd32(device, 0x15b4) & 0x3fff;
65 } else {
66 nv_wr32(device, 0x15b0, 0xff);
67 core_temp = nv_rd32(device, 0x15b4) & 0xff;
68 }
69
70 /* Setup the sensor if the temperature is 0 */
71 if (core_temp == 0)
72 core_temp = nv40_sensor_setup(dev);
73
74 if (sensor->slope_div == 0)
75 sensor->slope_div = 1;
76 if (sensor->offset_div == 0)
77 sensor->offset_div = 1;
78 if (sensor->slope_mult < 1)
79 sensor->slope_mult = 1;
80
81 core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
82 core_temp = core_temp + sensor->offset_mult / sensor->offset_div;
83 core_temp = core_temp + sensor->offset_constant - 8;
84
85 return core_temp;
86}
87
88int
89nv84_temp_get(struct drm_device *dev)
90{
91 struct nouveau_device *device = nouveau_dev(dev);
92 return nv_rd32(device, 0x20400);
93}
94
95void
96nouveau_temp_safety_checks(struct drm_device *dev)
97{
98 struct nouveau_pm *pm = nouveau_pm(dev);
99 struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
100
101 if (temps->critical > 120)
102 temps->critical = 120;
103 else if (temps->critical < 80)
104 temps->critical = 80;
105
106 if (temps->down_clock > 110)
107 temps->down_clock = 110;
108 else if (temps->down_clock < 60)
109 temps->down_clock = 60;
110}
111
112static bool
113probe_monitoring_device(struct nouveau_i2c_port *i2c,
114 struct i2c_board_info *info)
115{
116 struct i2c_client *client;
117
118 request_module("%s%s", I2C_MODULE_PREFIX, info->type);
119
120 client = i2c_new_device(&i2c->adapter, info);
121 if (!client)
122 return false;
123
124 if (!client->driver || client->driver->detect(client, info)) {
125 i2c_unregister_device(client);
126 return false;
127 }
128
129 return true;
130}
131
132static void
133nouveau_temp_probe_i2c(struct drm_device *dev)
134{
135 struct nouveau_device *device = nouveau_dev(dev);
136 struct nouveau_bios *bios = nouveau_bios(device);
137 struct nouveau_i2c *i2c = nouveau_i2c(device);
138 struct nvbios_extdev_func extdev_entry;
139 struct i2c_board_info info[] = {
140 { I2C_BOARD_INFO("w83l785ts", 0x2d) },
141 { I2C_BOARD_INFO("w83781d", 0x2d) },
142 { I2C_BOARD_INFO("adt7473", 0x2e) },
143 { I2C_BOARD_INFO("adt7473", 0x2d) },
144 { I2C_BOARD_INFO("adt7473", 0x2c) },
145 { I2C_BOARD_INFO("f75375", 0x2e) },
146 { I2C_BOARD_INFO("lm99", 0x4c) },
147 { I2C_BOARD_INFO("lm90", 0x4c) },
148 { I2C_BOARD_INFO("lm90", 0x4d) },
149 { I2C_BOARD_INFO("adm1021", 0x18) },
150 { I2C_BOARD_INFO("adm1021", 0x19) },
151 { I2C_BOARD_INFO("adm1021", 0x1a) },
152 { I2C_BOARD_INFO("adm1021", 0x29) },
153 { I2C_BOARD_INFO("adm1021", 0x2a) },
154 { I2C_BOARD_INFO("adm1021", 0x2b) },
155 { I2C_BOARD_INFO("adm1021", 0x4c) },
156 { I2C_BOARD_INFO("adm1021", 0x4d) },
157 { I2C_BOARD_INFO("adm1021", 0x4e) },
158 { I2C_BOARD_INFO("lm63", 0x18) },
159 { I2C_BOARD_INFO("lm63", 0x4e) },
160 { }
161 };
162
163 if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) {
164 struct i2c_board_info board[] = {
165 { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) },
166 { }
167 };
168
169 if (i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
170 board, probe_monitoring_device))
171 return;
172 }
173
174 if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) {
175 struct i2c_board_info board[] = {
176 { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) },
177 { }
178 };
179
180 if (i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
181 board, probe_monitoring_device))
182 return;
183 }
184
185 /* The vbios doesn't provide the address of an exisiting monitoring
186 device. Let's try our static list.
187 */
188 i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", info,
189 probe_monitoring_device);
190}
191
192void
193nouveau_temp_init(struct drm_device *dev)
194{
195 struct nouveau_drm *drm = nouveau_drm(dev);
196 struct nouveau_device *device = nv_device(drm->device);
197 struct nouveau_bios *bios = nouveau_bios(device);
198 struct nouveau_pm *pm = nouveau_pm(dev);
199 struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
200 struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
201 struct nvbios_therm_sensor bios_sensor;
202 struct nvbios_therm_fan bios_fan;
203
204 /* store some safe defaults */
205 sensor->offset_constant = 0;
206 sensor->offset_mult = 0;
207 sensor->offset_div = 1;
208 sensor->slope_mult = 1;
209 sensor->slope_div = 1;
210
211 if (!nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE,
212 &bios_sensor)) {
213 sensor->slope_mult = bios_sensor.slope_mult;
214 sensor->slope_div = bios_sensor.slope_div;
215 sensor->offset_mult = bios_sensor.offset_num;
216 sensor->offset_div = bios_sensor.offset_den;
217 sensor->offset_constant = bios_sensor.offset_constant;
218
219 temps->down_clock = bios_sensor.thrs_down_clock.temp;
220 temps->critical = bios_sensor.thrs_critical.temp;
221 }
222
223 if (nvbios_therm_fan_parse(bios, &bios_fan)) {
224 pm->fan.min_duty = bios_fan.min_duty;
225 pm->fan.max_duty = bios_fan.max_duty;
226 pm->fan.pwm_freq = bios_fan.pwm_freq;
227 }
228
229 nouveau_temp_safety_checks(dev);
230 nouveau_temp_probe_i2c(dev);
231}
232
233void
234nouveau_temp_fini(struct drm_device *dev)
235{
236
237}