aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
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
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')
-rw-r--r--drivers/gpu/drm/nouveau/Makefile8
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/device.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/therm.h58
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/base.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nv20.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nv40.c17
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nv50.c15
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nve0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/base.c140
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/fan.c172
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/ic.c116
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c163
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c130
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/priv.h66
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/temp.c81
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_perf.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.c244
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.h19
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_temp.c237
-rw-r--r--drivers/gpu/drm/nouveau/nv40_pm.c49
-rw-r--r--drivers/gpu/drm/nouveau/nv50_pm.c58
22 files changed, 1048 insertions, 542 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index 1b05d114dee..15d17e88743 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -91,6 +91,12 @@ nouveau-y += core/subdev/mc/nvc0.o
91nouveau-y += core/subdev/mxm/base.o 91nouveau-y += core/subdev/mxm/base.o
92nouveau-y += core/subdev/mxm/mxms.o 92nouveau-y += core/subdev/mxm/mxms.o
93nouveau-y += core/subdev/mxm/nv50.o 93nouveau-y += core/subdev/mxm/nv50.o
94nouveau-y += core/subdev/therm/base.o
95nouveau-y += core/subdev/therm/fan.o
96nouveau-y += core/subdev/therm/ic.o
97nouveau-y += core/subdev/therm/nv40.o
98nouveau-y += core/subdev/therm/nv50.o
99nouveau-y += core/subdev/therm/temp.o
94nouveau-y += core/subdev/timer/base.o 100nouveau-y += core/subdev/timer/base.o
95nouveau-y += core/subdev/timer/nv04.o 101nouveau-y += core/subdev/timer/nv04.o
96nouveau-y += core/subdev/vm/base.o 102nouveau-y += core/subdev/vm/base.o
@@ -173,7 +179,7 @@ nouveau-y += nv50_crtc.o nv50_dac.o nv50_sor.o nv50_cursor.o
173nouveau-y += nv50_evo.o 179nouveau-y += nv50_evo.o
174 180
175# drm/pm 181# drm/pm
176nouveau-y += nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o 182nouveau-y += nouveau_pm.o nouveau_volt.o nouveau_perf.o
177nouveau-y += nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o 183nouveau-y += nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o
178nouveau-y += nouveau_mem.o 184nouveau-y += nouveau_mem.o
179 185
diff --git a/drivers/gpu/drm/nouveau/core/include/core/device.h b/drivers/gpu/drm/nouveau/core/include/core/device.h
index c32f96a2270..57899fc3b87 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/device.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/device.h
@@ -22,7 +22,6 @@ enum nv_subdev_type {
22 NVDEV_SUBDEV_VM, 22 NVDEV_SUBDEV_VM,
23 NVDEV_SUBDEV_BAR, 23 NVDEV_SUBDEV_BAR,
24 NVDEV_SUBDEV_VOLT, 24 NVDEV_SUBDEV_VOLT,
25 NVDEV_SUBDEV_FAN0,
26 NVDEV_SUBDEV_THERM, 25 NVDEV_SUBDEV_THERM,
27 NVDEV_ENGINE_DMAOBJ, 26 NVDEV_ENGINE_DMAOBJ,
28 NVDEV_ENGINE_FIFO, 27 NVDEV_ENGINE_FIFO,
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h
new file mode 100644
index 00000000000..faee569fd45
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h
@@ -0,0 +1,58 @@
1#ifndef __NOUVEAU_THERM_H__
2#define __NOUVEAU_THERM_H__
3
4#include <core/device.h>
5#include <core/subdev.h>
6
7enum nouveau_therm_fan_mode {
8 FAN_CONTROL_NONE = 0,
9 FAN_CONTROL_MANUAL = 1,
10 FAN_CONTROL_NR,
11};
12
13enum nouveau_therm_attr_type {
14 NOUVEAU_THERM_ATTR_FAN_MIN_DUTY = 0,
15 NOUVEAU_THERM_ATTR_FAN_MAX_DUTY = 1,
16 NOUVEAU_THERM_ATTR_FAN_MODE = 2,
17
18 NOUVEAU_THERM_ATTR_THRS_FAN_BOOST = 10,
19 NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST = 11,
20 NOUVEAU_THERM_ATTR_THRS_DOWN_CLK = 12,
21 NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST = 13,
22 NOUVEAU_THERM_ATTR_THRS_CRITICAL = 14,
23 NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST = 15,
24 NOUVEAU_THERM_ATTR_THRS_SHUTDOWN = 16,
25 NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST = 17,
26};
27
28struct nouveau_therm {
29 struct nouveau_subdev base;
30
31 int (*fan_get)(struct nouveau_therm *);
32 int (*fan_set)(struct nouveau_therm *, int);
33 int (*fan_sense)(struct nouveau_therm *);
34
35 int (*temp_get)(struct nouveau_therm *);
36
37 int (*attr_get)(struct nouveau_therm *, enum nouveau_therm_attr_type);
38 int (*attr_set)(struct nouveau_therm *,
39 enum nouveau_therm_attr_type, int);
40};
41
42static inline struct nouveau_therm *
43nouveau_therm(void *obj)
44{
45 return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_THERM];
46}
47
48#define nouveau_therm_create(p,e,o,d) \
49 nouveau_subdev_create((p), (e), (o), 0, "THERM", "therm", d)
50#define nouveau_therm_destroy(p) \
51 nouveau_subdev_destroy(&(p)->base)
52
53#define _nouveau_therm_dtor _nouveau_subdev_dtor
54
55extern struct nouveau_oclass nv40_therm_oclass;
56extern struct nouveau_oclass nv50_therm_oclass;
57
58#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/base.c b/drivers/gpu/drm/nouveau/core/subdev/device/base.c
index cac67dc634b..7bf6f3760b9 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/base.c
@@ -71,7 +71,6 @@ static const u64 disable_map[] = {
71 [NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_DISABLE_CORE, 71 [NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_DISABLE_CORE,
72 [NVDEV_SUBDEV_BAR] = NV_DEVICE_DISABLE_CORE, 72 [NVDEV_SUBDEV_BAR] = NV_DEVICE_DISABLE_CORE,
73 [NVDEV_SUBDEV_VOLT] = NV_DEVICE_DISABLE_CORE, 73 [NVDEV_SUBDEV_VOLT] = NV_DEVICE_DISABLE_CORE,
74 [NVDEV_SUBDEV_FAN0] = NV_DEVICE_DISABLE_CORE,
75 [NVDEV_SUBDEV_CLOCK] = NV_DEVICE_DISABLE_CORE, 74 [NVDEV_SUBDEV_CLOCK] = NV_DEVICE_DISABLE_CORE,
76 [NVDEV_SUBDEV_THERM] = NV_DEVICE_DISABLE_CORE, 75 [NVDEV_SUBDEV_THERM] = NV_DEVICE_DISABLE_CORE,
77 [NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_DISABLE_CORE, 76 [NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_DISABLE_CORE,
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c
index 1c8681f36f1..5fa58b7369b 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c
@@ -27,6 +27,7 @@
27#include <subdev/gpio.h> 27#include <subdev/gpio.h>
28#include <subdev/i2c.h> 28#include <subdev/i2c.h>
29#include <subdev/clock.h> 29#include <subdev/clock.h>
30#include <subdev/therm.h>
30#include <subdev/devinit.h> 31#include <subdev/devinit.h>
31#include <subdev/mc.h> 32#include <subdev/mc.h>
32#include <subdev/timer.h> 33#include <subdev/timer.h>
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c
index c6005c27382..320ccc4ae05 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c
@@ -27,6 +27,7 @@
27#include <subdev/gpio.h> 27#include <subdev/gpio.h>
28#include <subdev/i2c.h> 28#include <subdev/i2c.h>
29#include <subdev/clock.h> 29#include <subdev/clock.h>
30#include <subdev/therm.h>
30#include <subdev/devinit.h> 31#include <subdev/devinit.h>
31#include <subdev/mc.h> 32#include <subdev/mc.h>
32#include <subdev/timer.h> 33#include <subdev/timer.h>
@@ -51,6 +52,7 @@ nv40_identify(struct nouveau_device *device)
51 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 52 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
52 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 53 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
53 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 54 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
55 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
54 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; 56 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
55 device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; 57 device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
56 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 58 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -70,6 +72,7 @@ nv40_identify(struct nouveau_device *device)
70 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 72 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
71 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 73 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
72 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 74 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
75 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
73 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; 76 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
74 device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; 77 device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
75 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 78 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -89,6 +92,7 @@ nv40_identify(struct nouveau_device *device)
89 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 92 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
90 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 93 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
91 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 94 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
95 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
92 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; 96 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
93 device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; 97 device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
94 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 98 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -108,6 +112,7 @@ nv40_identify(struct nouveau_device *device)
108 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 112 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
109 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 113 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
110 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 114 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
115 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
111 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; 116 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
112 device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; 117 device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
113 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 118 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -127,6 +132,7 @@ nv40_identify(struct nouveau_device *device)
127 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 132 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
128 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 133 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
129 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 134 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
135 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
130 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; 136 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
131 device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; 137 device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
132 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 138 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -146,6 +152,7 @@ nv40_identify(struct nouveau_device *device)
146 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 152 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
147 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 153 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
148 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 154 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
155 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
149 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; 156 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
150 device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; 157 device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
151 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 158 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -165,6 +172,7 @@ nv40_identify(struct nouveau_device *device)
165 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 172 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
166 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 173 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
167 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 174 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
175 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
168 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; 176 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
169 device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; 177 device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
170 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 178 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -184,6 +192,7 @@ nv40_identify(struct nouveau_device *device)
184 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 192 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
185 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 193 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
186 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 194 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
195 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
187 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; 196 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
188 device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; 197 device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
189 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 198 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -203,6 +212,7 @@ nv40_identify(struct nouveau_device *device)
203 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 212 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
204 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 213 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
205 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 214 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
215 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
206 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; 216 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
207 device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; 217 device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
208 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 218 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -222,6 +232,7 @@ nv40_identify(struct nouveau_device *device)
222 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 232 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
223 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 233 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
224 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 234 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
235 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
225 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; 236 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
226 device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; 237 device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
227 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 238 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -241,6 +252,7 @@ nv40_identify(struct nouveau_device *device)
241 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 252 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
242 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 253 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
243 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 254 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
255 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
244 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; 256 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
245 device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; 257 device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
246 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 258 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -260,6 +272,7 @@ nv40_identify(struct nouveau_device *device)
260 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 272 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
261 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 273 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
262 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 274 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
275 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
263 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; 276 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
264 device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; 277 device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
265 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 278 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -279,6 +292,7 @@ nv40_identify(struct nouveau_device *device)
279 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 292 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
280 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 293 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
281 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 294 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
295 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
282 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; 296 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
283 device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; 297 device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
284 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 298 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -298,6 +312,7 @@ nv40_identify(struct nouveau_device *device)
298 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 312 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
299 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 313 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
300 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 314 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
315 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
301 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; 316 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
302 device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; 317 device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
303 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 318 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -317,6 +332,7 @@ nv40_identify(struct nouveau_device *device)
317 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 332 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
318 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 333 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
319 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 334 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
335 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
320 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; 336 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
321 device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; 337 device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
322 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 338 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -336,6 +352,7 @@ nv40_identify(struct nouveau_device *device)
336 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; 352 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
337 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 353 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
338 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; 354 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
355 device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
339 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; 356 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
340 device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; 357 device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
341 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 358 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c
index 252e13c3c17..fec3bcc9a6f 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c
@@ -27,6 +27,7 @@
27#include <subdev/gpio.h> 27#include <subdev/gpio.h>
28#include <subdev/i2c.h> 28#include <subdev/i2c.h>
29#include <subdev/clock.h> 29#include <subdev/clock.h>
30#include <subdev/therm.h>
30#include <subdev/mxm.h> 31#include <subdev/mxm.h>
31#include <subdev/devinit.h> 32#include <subdev/devinit.h>
32#include <subdev/mc.h> 33#include <subdev/mc.h>
@@ -58,6 +59,7 @@ nv50_identify(struct nouveau_device *device)
58 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 59 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
59 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 60 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
60 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; 61 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
62 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
61 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 63 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
62 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 64 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
63 device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; 65 device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
@@ -79,6 +81,7 @@ nv50_identify(struct nouveau_device *device)
79 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 81 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
80 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 82 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
81 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; 83 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
84 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
82 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 85 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
83 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 86 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
84 device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; 87 device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
@@ -103,6 +106,7 @@ nv50_identify(struct nouveau_device *device)
103 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 106 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
104 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 107 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
105 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; 108 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
109 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
106 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 110 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
107 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 111 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
108 device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; 112 device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
@@ -127,6 +131,7 @@ nv50_identify(struct nouveau_device *device)
127 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 131 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
128 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 132 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
129 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; 133 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
134 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
130 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 135 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
131 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 136 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
132 device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; 137 device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
@@ -151,6 +156,7 @@ nv50_identify(struct nouveau_device *device)
151 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 156 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
152 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 157 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
153 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; 158 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
159 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
154 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 160 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
155 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 161 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
156 device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; 162 device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
@@ -175,6 +181,7 @@ nv50_identify(struct nouveau_device *device)
175 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 181 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
176 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 182 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
177 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; 183 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
184 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
178 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 185 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
179 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 186 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
180 device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; 187 device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
@@ -199,6 +206,7 @@ nv50_identify(struct nouveau_device *device)
199 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 206 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
200 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 207 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
201 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; 208 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
209 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
202 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 210 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
203 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 211 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
204 device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; 212 device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
@@ -223,6 +231,7 @@ nv50_identify(struct nouveau_device *device)
223 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 231 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
224 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 232 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
225 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; 233 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
234 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
226 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 235 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
227 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 236 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
228 device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; 237 device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
@@ -247,6 +256,7 @@ nv50_identify(struct nouveau_device *device)
247 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 256 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
248 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 257 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
249 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; 258 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
259 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
250 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 260 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
251 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 261 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
252 device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; 262 device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
@@ -271,6 +281,7 @@ nv50_identify(struct nouveau_device *device)
271 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 281 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
272 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 282 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
273 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; 283 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
284 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
274 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 285 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
275 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 286 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
276 device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; 287 device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
@@ -295,6 +306,7 @@ nv50_identify(struct nouveau_device *device)
295 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 306 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
296 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 307 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
297 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; 308 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
309 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
298 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 310 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
299 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 311 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
300 device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; 312 device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
@@ -320,6 +332,7 @@ nv50_identify(struct nouveau_device *device)
320 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 332 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
321 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 333 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
322 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; 334 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
335 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
323 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 336 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
324 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 337 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
325 device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; 338 device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
@@ -344,6 +357,7 @@ nv50_identify(struct nouveau_device *device)
344 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 357 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
345 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 358 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
346 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; 359 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
360 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
347 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 361 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
348 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 362 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
349 device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; 363 device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
@@ -368,6 +382,7 @@ nv50_identify(struct nouveau_device *device)
368 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 382 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
369 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 383 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
370 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; 384 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
385 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
371 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 386 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
372 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 387 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
373 device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; 388 device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c
index 8c14b3849fe..246bd081a01 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c
@@ -27,6 +27,7 @@
27#include <subdev/gpio.h> 27#include <subdev/gpio.h>
28#include <subdev/i2c.h> 28#include <subdev/i2c.h>
29#include <subdev/clock.h> 29#include <subdev/clock.h>
30#include <subdev/therm.h>
30#include <subdev/mxm.h> 31#include <subdev/mxm.h>
31#include <subdev/devinit.h> 32#include <subdev/devinit.h>
32#include <subdev/mc.h> 33#include <subdev/mc.h>
@@ -57,6 +58,7 @@ nvc0_identify(struct nouveau_device *device)
57 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 58 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
58 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 59 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
59 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 60 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
61 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
60 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 62 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
61 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 63 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
62 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; 64 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
@@ -83,6 +85,7 @@ nvc0_identify(struct nouveau_device *device)
83 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 85 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
84 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 86 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
85 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 87 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
88 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
86 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 89 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
87 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 90 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
88 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; 91 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
@@ -109,6 +112,7 @@ nvc0_identify(struct nouveau_device *device)
109 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 112 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
110 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 113 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
111 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 114 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
115 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
112 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 116 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
113 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 117 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
114 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; 118 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
@@ -135,6 +139,7 @@ nvc0_identify(struct nouveau_device *device)
135 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 139 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
136 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 140 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
137 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 141 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
142 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
138 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 143 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
139 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 144 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
140 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; 145 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
@@ -161,6 +166,7 @@ nvc0_identify(struct nouveau_device *device)
161 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 166 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
162 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 167 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
163 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 168 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
169 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
164 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 170 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
165 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 171 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
166 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; 172 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
@@ -187,6 +193,7 @@ nvc0_identify(struct nouveau_device *device)
187 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 193 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
188 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 194 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
189 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 195 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
196 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
190 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 197 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
191 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 198 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
192 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; 199 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
@@ -213,6 +220,7 @@ nvc0_identify(struct nouveau_device *device)
213 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; 220 device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
214 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 221 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
215 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 222 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
223 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
216 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 224 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
217 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 225 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
218 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; 226 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
@@ -239,6 +247,7 @@ nvc0_identify(struct nouveau_device *device)
239 device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass; 247 device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass;
240 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 248 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
241 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 249 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
250 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
242 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 251 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
243 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 252 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
244 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; 253 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
index 0d9d86b8124..4a280b7ab85 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
@@ -27,6 +27,7 @@
27#include <subdev/gpio.h> 27#include <subdev/gpio.h>
28#include <subdev/i2c.h> 28#include <subdev/i2c.h>
29#include <subdev/clock.h> 29#include <subdev/clock.h>
30#include <subdev/therm.h>
30#include <subdev/mxm.h> 31#include <subdev/mxm.h>
31#include <subdev/devinit.h> 32#include <subdev/devinit.h>
32#include <subdev/mc.h> 33#include <subdev/mc.h>
@@ -55,6 +56,7 @@ nve0_identify(struct nouveau_device *device)
55 device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass; 56 device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass;
56 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 57 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
57 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 58 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
59 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
58 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 60 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
59 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 61 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
60 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; 62 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
@@ -79,6 +81,7 @@ nve0_identify(struct nouveau_device *device)
79 device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass; 81 device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass;
80 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; 82 device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
81 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; 83 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
84 device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
82 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 85 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
83 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; 86 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
84 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; 87 device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c
new file mode 100644
index 00000000000..6502dfb95dd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c
@@ -0,0 +1,140 @@
1/*
2 * Copyright 2012 The 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 <core/object.h>
26#include <core/device.h>
27
28#include <subdev/bios.h>
29
30#include "priv.h"
31
32int
33nouveau_therm_attr_get(struct nouveau_therm *therm,
34 enum nouveau_therm_attr_type type)
35{
36 struct nouveau_therm_priv *priv = (void *)therm;
37
38 switch (type) {
39 case NOUVEAU_THERM_ATTR_FAN_MIN_DUTY:
40 return priv->bios_fan.min_duty;
41 case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY:
42 return priv->bios_fan.max_duty;
43 case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST:
44 return priv->bios_sensor.thrs_fan_boost.temp;
45 case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST:
46 return priv->bios_sensor.thrs_fan_boost.hysteresis;
47 case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK:
48 return priv->bios_sensor.thrs_down_clock.temp;
49 case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST:
50 return priv->bios_sensor.thrs_down_clock.hysteresis;
51 case NOUVEAU_THERM_ATTR_THRS_CRITICAL:
52 return priv->bios_sensor.thrs_critical.temp;
53 case NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST:
54 return priv->bios_sensor.thrs_critical.hysteresis;
55 case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN:
56 return priv->bios_sensor.thrs_shutdown.temp;
57 case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST:
58 return priv->bios_sensor.thrs_shutdown.hysteresis;
59 }
60
61 return -EINVAL;
62}
63
64int
65nouveau_therm_attr_set(struct nouveau_therm *therm,
66 enum nouveau_therm_attr_type type, int value)
67{
68 struct nouveau_therm_priv *priv = (void *)therm;
69
70 switch (type) {
71 case NOUVEAU_THERM_ATTR_FAN_MIN_DUTY:
72 if (value < 0)
73 value = 0;
74 if (value > priv->bios_fan.max_duty)
75 value = priv->bios_fan.max_duty;
76 priv->bios_fan.min_duty = value;
77 return 0;
78 case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY:
79 if (value < 0)
80 value = 0;
81 if (value < priv->bios_fan.min_duty)
82 value = priv->bios_fan.min_duty;
83 priv->bios_fan.max_duty = value;
84 return 0;
85 case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST:
86 priv->bios_sensor.thrs_fan_boost.temp = value;
87 return 0;
88 case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST:
89 priv->bios_sensor.thrs_fan_boost.hysteresis = value;
90 return 0;
91 case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK:
92 priv->bios_sensor.thrs_down_clock.temp = value;
93 return 0;
94 case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST:
95 priv->bios_sensor.thrs_down_clock.hysteresis = value;
96 return 0;
97 case NOUVEAU_THERM_ATTR_THRS_CRITICAL:
98 priv->bios_sensor.thrs_critical.temp = value;
99 return 0;
100 case NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST:
101 priv->bios_sensor.thrs_critical.hysteresis = value;
102 return 0;
103 case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN:
104 priv->bios_sensor.thrs_shutdown.temp = value;
105 return 0;
106 case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST:
107 priv->bios_sensor.thrs_shutdown.hysteresis = value;
108 return 0;
109 }
110
111 return -EINVAL;
112}
113
114int
115nouveau_therm_init(struct nouveau_object *object)
116{
117 struct nouveau_therm *therm = (void *)object;
118 struct nouveau_therm_priv *priv = (void *)therm;
119 int ret;
120
121 ret = nouveau_subdev_init(&therm->base);
122 if (ret)
123 return ret;
124
125 if (priv->fan.percent >= 0)
126 therm->fan_set(therm, priv->fan.percent);
127
128 return 0;
129}
130
131int
132nouveau_therm_fini(struct nouveau_object *object, bool suspend)
133{
134 struct nouveau_therm *therm = (void *)object;
135 struct nouveau_therm_priv *priv = (void *)therm;
136
137 priv->fan.percent = therm->fan_get(therm);
138
139 return nouveau_subdev_fini(&therm->base, suspend);
140}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c
new file mode 100644
index 00000000000..9ad6e166dd7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c
@@ -0,0 +1,172 @@
1/*
2 * Copyright 2012 Red Hat 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: Ben Skeggs
23 * Martin Peres
24 */
25
26#include "priv.h"
27
28#include <core/object.h>
29#include <core/device.h>
30#include <subdev/gpio.h>
31#include <subdev/timer.h>
32
33int
34nouveau_therm_fan_get(struct nouveau_therm *therm)
35{
36 struct nouveau_therm_priv *priv = (void *)therm;
37 struct nouveau_gpio *gpio = nouveau_gpio(therm);
38 struct dcb_gpio_func func;
39 int card_type = nv_device(therm)->card_type;
40 u32 divs, duty;
41 int ret;
42
43 if (!priv->fan.pwm_get)
44 return -ENODEV;
45
46 ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func);
47 if (ret == 0) {
48 ret = priv->fan.pwm_get(therm, func.line, &divs, &duty);
49 if (ret == 0 && divs) {
50 divs = max(divs, duty);
51 if (card_type <= NV_40 || (func.log[0] & 1))
52 duty = divs - duty;
53 return (duty * 100) / divs;
54 }
55
56 return gpio->get(gpio, 0, func.func, func.line) * 100;
57 }
58
59 return -ENODEV;
60}
61
62int
63nouveau_therm_fan_set(struct nouveau_therm *therm, int percent)
64{
65 struct nouveau_therm_priv *priv = (void *)therm;
66 struct nouveau_gpio *gpio = nouveau_gpio(therm);
67 struct dcb_gpio_func func;
68 int card_type = nv_device(therm)->card_type;
69 u32 divs, duty;
70 int ret;
71
72 if (!priv->fan.pwm_set)
73 return -ENODEV;
74
75 if (percent < priv->bios_fan.min_duty)
76 percent = priv->bios_fan.min_duty;
77 if (percent > priv->bios_fan.max_duty)
78 percent = priv->bios_fan.max_duty;
79
80 ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func);
81 if (ret == 0) {
82 divs = priv->bios_perf_fan.pwm_divisor;
83 if (priv->bios_fan.pwm_freq) {
84 /*XXX: PNVIO clock more than likely... */
85 divs = 135000 /priv->bios_fan.pwm_freq;
86 if (nv_device(therm)->chipset < 0xa3)
87 divs /= 4;
88 }
89
90 duty = ((divs * percent) + 99) / 100;
91 if (card_type <= NV_40 || (func.log[0] & 1))
92 duty = divs - duty;
93
94 ret = priv->fan.pwm_set(therm, func.line, divs, duty);
95 return ret;
96 }
97
98 return -ENODEV;
99}
100
101int
102nouveau_therm_fan_sense(struct nouveau_therm *therm)
103{
104 struct nouveau_timer *ptimer = nouveau_timer(therm);
105 struct nouveau_gpio *gpio = nouveau_gpio(therm);
106 struct dcb_gpio_func func;
107 u32 cycles, cur, prev;
108 u64 start;
109
110 if (gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &func))
111 return -ENODEV;
112
113 /* Monitor the GPIO input 0x3b for 250ms.
114 * When the fan spins, it changes the value of GPIO FAN_SENSE.
115 * We get 4 changes (0 -> 1 -> 0 -> 1 -> [...]) per complete rotation.
116 */
117 start = ptimer->read(ptimer);
118 prev = gpio->get(gpio, 0, func.func, func.line);
119 cycles = 0;
120 do {
121 cur = gpio->get(gpio, 0, func.func, func.line);
122 if (prev != cur) {
123 cycles++;
124 prev = cur;
125 }
126
127 usleep_range(500, 1000); /* supports 0 < rpm < 7500 */
128 } while (ptimer->read(ptimer) - start < 250000000);
129
130 /* interpolate to get rpm */
131 return cycles / 4 * 4 * 60;
132}
133
134static void
135nouveau_therm_fan_set_defaults(struct nouveau_therm *therm)
136{
137 struct nouveau_therm_priv *priv = (void *)therm;
138
139 priv->bios_fan.pwm_freq = 0;
140 priv->bios_fan.min_duty = 0;
141 priv->bios_fan.max_duty = 100;
142}
143
144
145static void
146nouveau_therm_fan_safety_checks(struct nouveau_therm *therm)
147{
148 struct nouveau_therm_priv *priv = (void *)therm;
149
150 if (priv->bios_fan.min_duty > 100)
151 priv->bios_fan.min_duty = 100;
152 if (priv->bios_fan.max_duty > 100)
153 priv->bios_fan.max_duty = 100;
154
155 if (priv->bios_fan.min_duty > priv->bios_fan.max_duty)
156 priv->bios_fan.min_duty = priv->bios_fan.max_duty;
157}
158
159int
160nouveau_therm_fan_ctor(struct nouveau_therm *therm)
161{
162 struct nouveau_therm_priv *priv = (void *)therm;
163 struct nouveau_bios *bios = nouveau_bios(therm);
164
165 nouveau_therm_fan_set_defaults(therm);
166 nvbios_perf_fan_parse(bios, &priv->bios_perf_fan);
167 if (nvbios_therm_fan_parse(bios, &priv->bios_fan))
168 nv_error(therm, "parsing the thermal table failed\n");
169 nouveau_therm_fan_safety_checks(therm);
170
171 return 0;
172}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c b/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c
new file mode 100644
index 00000000000..e512ff0aae6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c
@@ -0,0 +1,116 @@
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 "priv.h"
26
27#include <subdev/i2c.h>
28#include <subdev/bios/extdev.h>
29
30static bool
31probe_monitoring_device(struct nouveau_i2c_port *i2c,
32 struct i2c_board_info *info)
33{
34 struct nouveau_therm_priv *priv = (void *)nouveau_therm(i2c->i2c);
35 struct i2c_client *client;
36
37 request_module("%s%s", I2C_MODULE_PREFIX, info->type);
38
39 client = i2c_new_device(&i2c->adapter, info);
40 if (!client)
41 return false;
42
43 if (!client->driver || client->driver->detect(client, info)) {
44 i2c_unregister_device(client);
45 return false;
46 }
47
48 nv_info(priv,
49 "Found an %s at address 0x%x (controlled by lm_sensors)\n",
50 info->type, info->addr);
51 priv->ic = client;
52
53 return true;
54}
55
56void
57nouveau_therm_ic_ctor(struct nouveau_therm *therm)
58{
59 struct nouveau_therm_priv *priv = (void *)therm;
60 struct nouveau_bios *bios = nouveau_bios(therm);
61 struct nouveau_i2c *i2c = nouveau_i2c(therm);
62 struct nvbios_extdev_func extdev_entry;
63 struct i2c_board_info info[] = {
64 { I2C_BOARD_INFO("w83l785ts", 0x2d) },
65 { I2C_BOARD_INFO("w83781d", 0x2d) },
66 { I2C_BOARD_INFO("adt7473", 0x2e) },
67 { I2C_BOARD_INFO("adt7473", 0x2d) },
68 { I2C_BOARD_INFO("adt7473", 0x2c) },
69 { I2C_BOARD_INFO("f75375", 0x2e) },
70 { I2C_BOARD_INFO("lm99", 0x4c) },
71 { I2C_BOARD_INFO("lm90", 0x4c) },
72 { I2C_BOARD_INFO("lm90", 0x4d) },
73 { I2C_BOARD_INFO("adm1021", 0x18) },
74 { I2C_BOARD_INFO("adm1021", 0x19) },
75 { I2C_BOARD_INFO("adm1021", 0x1a) },
76 { I2C_BOARD_INFO("adm1021", 0x29) },
77 { I2C_BOARD_INFO("adm1021", 0x2a) },
78 { I2C_BOARD_INFO("adm1021", 0x2b) },
79 { I2C_BOARD_INFO("adm1021", 0x4c) },
80 { I2C_BOARD_INFO("adm1021", 0x4d) },
81 { I2C_BOARD_INFO("adm1021", 0x4e) },
82 { I2C_BOARD_INFO("lm63", 0x18) },
83 { I2C_BOARD_INFO("lm63", 0x4e) },
84 { }
85 };
86
87 if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) {
88 struct i2c_board_info board[] = {
89 { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) },
90 { }
91 };
92
93 i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
94 board, probe_monitoring_device);
95 if (priv->ic)
96 return;
97 }
98
99 if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) {
100 struct i2c_board_info board[] = {
101 { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) },
102 { }
103 };
104
105 i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
106 board, probe_monitoring_device);
107 if (priv->ic)
108 return;
109 }
110
111 /* The vbios doesn't provide the address of an exisiting monitoring
112 device. Let's try our static list.
113 */
114 i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", info,
115 probe_monitoring_device);
116}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c
new file mode 100644
index 00000000000..9021b541da8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c
@@ -0,0 +1,163 @@
1/*
2 * Copyright 2012 Red Hat 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: Ben Skeggs
23 * Martin Peres
24 */
25
26#include "priv.h"
27
28static int
29nv40_sensor_setup(struct nouveau_therm *therm)
30{
31 struct nouveau_device *device = nv_device(therm);
32
33 /* enable ADC readout and disable the ALARM threshold */
34 if (device->chipset >= 0x46) {
35 nv_mask(therm, 0x15b8, 0x80000000, 0);
36 nv_wr32(therm, 0x15b0, 0x80003fff);
37 return nv_rd32(therm, 0x15b4) & 0x3fff;
38 } else {
39 nv_wr32(therm, 0x15b0, 0xff);
40 return nv_rd32(therm, 0x15b4) & 0xff;
41 }
42}
43
44static int
45nv40_temp_get(struct nouveau_therm *therm)
46{
47 struct nouveau_therm_priv *priv = (void *)therm;
48 struct nouveau_device *device = nv_device(therm);
49 struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
50 int core_temp;
51
52 if (device->chipset >= 0x46) {
53 nv_wr32(therm, 0x15b0, 0x80003fff);
54 core_temp = nv_rd32(therm, 0x15b4) & 0x3fff;
55 } else {
56 nv_wr32(therm, 0x15b0, 0xff);
57 core_temp = nv_rd32(therm, 0x15b4) & 0xff;
58 }
59
60 /* Setup the sensor if the temperature is 0 */
61 if (core_temp == 0)
62 core_temp = nv40_sensor_setup(therm);
63
64 if (sensor->slope_div == 0)
65 sensor->slope_div = 1;
66 if (sensor->offset_den == 0)
67 sensor->offset_den = 1;
68 if (sensor->slope_mult < 1)
69 sensor->slope_mult = 1;
70
71 core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
72 core_temp = core_temp + sensor->offset_num / sensor->offset_den;
73 core_temp = core_temp + sensor->offset_constant - 8;
74
75 return core_temp;
76}
77
78int
79nv40_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
80{
81 if (line == 2) {
82 u32 reg = nv_rd32(therm, 0x0010f0);
83 if (reg & 0x80000000) {
84 *duty = (reg & 0x7fff0000) >> 16;
85 *divs = (reg & 0x00007fff);
86 return 0;
87 }
88 } else
89 if (line == 9) {
90 u32 reg = nv_rd32(therm, 0x0015f4);
91 if (reg & 0x80000000) {
92 *divs = nv_rd32(therm, 0x0015f8);
93 *duty = (reg & 0x7fffffff);
94 return 0;
95 }
96 } else {
97 nv_error(therm, "unknown pwm ctrl for gpio %d\n", line);
98 return -ENODEV;
99 }
100
101 return -EINVAL;
102}
103
104int
105nv40_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
106{
107 if (line == 2) {
108 nv_wr32(therm, 0x0010f0, 0x80000000 | (duty << 16) | divs);
109 } else
110 if (line == 9) {
111 nv_wr32(therm, 0x0015f8, divs);
112 nv_wr32(therm, 0x0015f4, duty | 0x80000000);
113 } else {
114 nv_error(therm, "unknown pwm ctrl for gpio %d\n", line);
115 return -ENODEV;
116 }
117
118 return 0;
119}
120
121static int
122nv40_therm_ctor(struct nouveau_object *parent,
123 struct nouveau_object *engine,
124 struct nouveau_oclass *oclass, void *data, u32 size,
125 struct nouveau_object **pobject)
126{
127 struct nouveau_therm_priv *priv;
128 struct nouveau_therm *therm;
129 int ret;
130
131 ret = nouveau_therm_create(parent, engine, oclass, &priv);
132 *pobject = nv_object(priv);
133 therm = (void *) priv;
134 if (ret)
135 return ret;
136
137 nouveau_therm_ic_ctor(therm);
138 nouveau_therm_sensor_ctor(therm);
139 nouveau_therm_fan_ctor(therm);
140
141 priv->fan.pwm_get = nv40_fan_pwm_get;
142 priv->fan.pwm_set = nv40_fan_pwm_set;
143
144 therm->temp_get = nv40_temp_get;
145 therm->fan_get = nouveau_therm_fan_get;
146 therm->fan_set = nouveau_therm_fan_set;
147 therm->fan_sense = nouveau_therm_fan_sense;
148 therm->attr_get = nouveau_therm_attr_get;
149 therm->attr_set = nouveau_therm_attr_set;
150
151 return 0;
152}
153
154struct nouveau_oclass
155nv40_therm_oclass = {
156 .handle = NV_SUBDEV(THERM, 0x40),
157 .ofuncs = &(struct nouveau_ofuncs) {
158 .ctor = nv40_therm_ctor,
159 .dtor = _nouveau_therm_dtor,
160 .init = nouveau_therm_init,
161 .fini = nouveau_therm_fini,
162 },
163}; \ No newline at end of file
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
new file mode 100644
index 00000000000..f7f51f35d18
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
@@ -0,0 +1,130 @@
1/*
2 * Copyright 2012 Red Hat 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: Ben Skeggs
23 * Martin Peres
24 */
25
26#include "priv.h"
27
28static int
29pwm_info(struct nouveau_therm *therm, int *line, int *ctrl, int *indx)
30{
31 if (*line == 0x04) {
32 *ctrl = 0x00e100;
33 *line = 4;
34 *indx = 0;
35 } else
36 if (*line == 0x09) {
37 *ctrl = 0x00e100;
38 *line = 9;
39 *indx = 1;
40 } else
41 if (*line == 0x10) {
42 *ctrl = 0x00e28c;
43 *line = 0;
44 *indx = 0;
45 } else {
46 nv_error(therm, "unknown pwm ctrl for gpio %d\n", *line);
47 return -ENODEV;
48 }
49
50 return 0;
51}
52
53int
54nv50_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
55{
56 int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
57 if (ret)
58 return ret;
59
60 if (nv_rd32(therm, ctrl) & (1 << line)) {
61 *divs = nv_rd32(therm, 0x00e114 + (id * 8));
62 *duty = nv_rd32(therm, 0x00e118 + (id * 8));
63 return 0;
64 }
65
66 return -EINVAL;
67}
68
69int
70nv50_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
71{
72 int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
73 if (ret)
74 return ret;
75
76 nv_mask(therm, ctrl, 0x00010001 << line, 0x00000001 << line);
77 nv_wr32(therm, 0x00e114 + (id * 8), divs);
78 nv_wr32(therm, 0x00e118 + (id * 8), duty | 0x80000000);
79 return 0;
80}
81
82int
83nv50_temp_get(struct nouveau_therm *therm)
84{
85 return nv_rd32(therm, 0x20400);
86}
87
88static int
89nv50_therm_ctor(struct nouveau_object *parent,
90 struct nouveau_object *engine,
91 struct nouveau_oclass *oclass, void *data, u32 size,
92 struct nouveau_object **pobject)
93{
94 struct nouveau_therm_priv *priv;
95 struct nouveau_therm *therm;
96 int ret;
97
98 ret = nouveau_therm_create(parent, engine, oclass, &priv);
99 *pobject = nv_object(priv);
100 therm = (void *) priv;
101 if (ret)
102 return ret;
103
104 nouveau_therm_ic_ctor(therm);
105 nouveau_therm_sensor_ctor(therm);
106 nouveau_therm_fan_ctor(therm);
107
108 priv->fan.pwm_get = nv50_fan_pwm_get;
109 priv->fan.pwm_set = nv50_fan_pwm_set;
110
111 therm->temp_get = nv50_temp_get;
112 therm->fan_get = nouveau_therm_fan_get;
113 therm->fan_set = nouveau_therm_fan_set;
114 therm->fan_sense = nouveau_therm_fan_sense;
115 therm->attr_get = nouveau_therm_attr_get;
116 therm->attr_set = nouveau_therm_attr_set;
117
118 return 0;
119}
120
121struct nouveau_oclass
122nv50_therm_oclass = {
123 .handle = NV_SUBDEV(THERM, 0x50),
124 .ofuncs = &(struct nouveau_ofuncs) {
125 .ctor = nv50_therm_ctor,
126 .dtor = _nouveau_therm_dtor,
127 .init = nouveau_therm_init,
128 .fini = nouveau_therm_fini,
129 },
130};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h
new file mode 100644
index 00000000000..b7207b4524f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h
@@ -0,0 +1,66 @@
1/*
2 * Copyright 2012 The 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/therm.h>
26
27#include <subdev/bios/extdev.h>
28#include <subdev/bios/perf.h>
29#include <subdev/bios/therm.h>
30
31struct nouveau_therm_priv {
32 struct nouveau_therm base;
33
34 /* bios */
35 struct nvbios_therm_sensor bios_sensor;
36 struct nvbios_therm_fan bios_fan;
37 struct nvbios_perf_fan bios_perf_fan;
38
39 /* fan priv */
40 struct {
41 int percent;
42
43 int (*pwm_get)(struct nouveau_therm *, int line, u32*, u32*);
44 int (*pwm_set)(struct nouveau_therm *, int line, u32, u32);
45 } fan;
46
47 /* ic */
48 struct i2c_client *ic;
49};
50
51int nouveau_therm_init(struct nouveau_object *object);
52int nouveau_therm_fini(struct nouveau_object *object, bool suspend);
53int nouveau_therm_attr_get(struct nouveau_therm *therm,
54 enum nouveau_therm_attr_type type);
55int nouveau_therm_attr_set(struct nouveau_therm *therm,
56 enum nouveau_therm_attr_type type, int value);
57
58void nouveau_therm_ic_ctor(struct nouveau_therm *therm);
59
60int nouveau_therm_sensor_ctor(struct nouveau_therm *therm);
61
62int nouveau_therm_fan_ctor(struct nouveau_therm *therm);
63int nouveau_therm_fan_get(struct nouveau_therm *therm);
64int nouveau_therm_fan_set(struct nouveau_therm *therm, int percent);
65
66int nouveau_therm_fan_sense(struct nouveau_therm *therm);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c
new file mode 100644
index 00000000000..204282301fb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c
@@ -0,0 +1,81 @@
1/*
2 * Copyright 2012 The 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 "priv.h"
26
27#include <core/object.h>
28#include <core/device.h>
29
30#include <subdev/bios.h>
31
32static void
33nouveau_therm_temp_set_defaults(struct nouveau_therm *therm)
34{
35 struct nouveau_therm_priv *priv = (void *)therm;
36
37 priv->bios_sensor.slope_mult = 1;
38 priv->bios_sensor.slope_div = 1;
39 priv->bios_sensor.offset_num = 0;
40 priv->bios_sensor.offset_den = 1;
41 priv->bios_sensor.offset_constant = 0;
42
43 priv->bios_sensor.thrs_fan_boost.temp = 90;
44 priv->bios_sensor.thrs_fan_boost.hysteresis = 3;
45
46 priv->bios_sensor.thrs_down_clock.temp = 95;
47 priv->bios_sensor.thrs_down_clock.hysteresis = 3;
48
49 priv->bios_sensor.thrs_critical.temp = 105;
50 priv->bios_sensor.thrs_critical.hysteresis = 5;
51
52 priv->bios_sensor.thrs_shutdown.temp = 135;
53 priv->bios_sensor.thrs_shutdown.hysteresis = 5; /*not that it matters */
54}
55
56
57static void
58nouveau_therm_temp_safety_checks(struct nouveau_therm *therm)
59{
60 struct nouveau_therm_priv *priv = (void *)therm;
61
62 if (!priv->bios_sensor.slope_div)
63 priv->bios_sensor.slope_div = 1;
64 if (!priv->bios_sensor.offset_den)
65 priv->bios_sensor.offset_den = 1;
66}
67
68int
69nouveau_therm_sensor_ctor(struct nouveau_therm *therm)
70{
71 struct nouveau_therm_priv *priv = (void *)therm;
72 struct nouveau_bios *bios = nouveau_bios(therm);
73
74 nouveau_therm_temp_set_defaults(therm);
75 if (nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE,
76 &priv->bios_sensor))
77 nv_error(therm, "nvbios_therm_sensor_parse failed\n");
78 nouveau_therm_temp_safety_checks(therm);
79
80 return 0;
81}
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c
index b5c6a43511d..a11d2e4f8f6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_perf.c
+++ b/drivers/gpu/drm/nouveau/nouveau_perf.c
@@ -304,8 +304,6 @@ nouveau_perf_init(struct drm_device *dev)
304 } 304 }
305 305
306 perf = nouveau_perf_table(dev, &ver); 306 perf = nouveau_perf_table(dev, &ver);
307 if (ver >= 0x20 && ver < 0x40)
308 pm->fan.pwm_divisor = ROM16(perf[6]);
309 307
310 while ((perf = nouveau_perf_entry(dev, ++i, &ver, &hdr, &cnt, &len))) { 308 while ((perf = nouveau_perf_entry(dev, ++i, &ver, &hdr, &cnt, &len))) {
311 struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl]; 309 struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index bdd50953488..8317e82b86c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -34,9 +34,9 @@
34#include "nouveau_drm.h" 34#include "nouveau_drm.h"
35#include "nouveau_pm.h" 35#include "nouveau_pm.h"
36 36
37#include <subdev/bios/gpio.h>
38#include <subdev/gpio.h> 37#include <subdev/gpio.h>
39#include <subdev/timer.h> 38#include <subdev/timer.h>
39#include <subdev/therm.h>
40 40
41MODULE_PARM_DESC(perflvl, "Performance level (default: boot)"); 41MODULE_PARM_DESC(perflvl, "Performance level (default: boot)");
42static char *nouveau_perflvl; 42static char *nouveau_perflvl;
@@ -47,86 +47,21 @@ static int nouveau_perflvl_wr;
47module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400); 47module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400);
48 48
49static int 49static int
50nouveau_pwmfan_get(struct drm_device *dev)
51{
52 struct nouveau_pm *pm = nouveau_pm(dev);
53 struct nouveau_drm *drm = nouveau_drm(dev);
54 struct nouveau_device *device = nv_device(drm->device);
55 struct nouveau_gpio *gpio = nouveau_gpio(device);
56 struct dcb_gpio_func func;
57 u32 divs, duty;
58 int ret;
59
60 if (!pm->pwm_get)
61 return -ENODEV;
62
63 ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func);
64 if (ret == 0) {
65 ret = pm->pwm_get(dev, func.line, &divs, &duty);
66 if (ret == 0 && divs) {
67 divs = max(divs, duty);
68 if (device->card_type <= NV_40 || (func.log[0] & 1))
69 duty = divs - duty;
70 return (duty * 100) / divs;
71 }
72
73 return gpio->get(gpio, 0, func.func, func.line) * 100;
74 }
75
76 return -ENODEV;
77}
78
79static int
80nouveau_pwmfan_set(struct drm_device *dev, int percent)
81{
82 struct nouveau_pm *pm = nouveau_pm(dev);
83 struct nouveau_drm *drm = nouveau_drm(dev);
84 struct nouveau_device *device = nv_device(drm->device);
85 struct nouveau_gpio *gpio = nouveau_gpio(device);
86 struct dcb_gpio_func func;
87 u32 divs, duty;
88 int ret;
89
90 if (!pm->pwm_set)
91 return -ENODEV;
92
93 ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func);
94 if (ret == 0) {
95 divs = pm->fan.pwm_divisor;
96 if (pm->fan.pwm_freq) {
97 /*XXX: PNVIO clock more than likely... */
98 divs = 135000 / pm->fan.pwm_freq;
99 if (nv_device(drm->device)->chipset < 0xa3)
100 divs /= 4;
101 }
102
103 duty = ((divs * percent) + 99) / 100;
104 if (device->card_type <= NV_40 || (func.log[0] & 1))
105 duty = divs - duty;
106
107 ret = pm->pwm_set(dev, func.line, divs, duty);
108 if (!ret)
109 pm->fan.percent = percent;
110 return ret;
111 }
112
113 return -ENODEV;
114}
115
116static int
117nouveau_pm_perflvl_aux(struct drm_device *dev, struct nouveau_pm_level *perflvl, 50nouveau_pm_perflvl_aux(struct drm_device *dev, struct nouveau_pm_level *perflvl,
118 struct nouveau_pm_level *a, struct nouveau_pm_level *b) 51 struct nouveau_pm_level *a, struct nouveau_pm_level *b)
119{ 52{
120 struct nouveau_drm *drm = nouveau_drm(dev); 53 struct nouveau_drm *drm = nouveau_drm(dev);
121 struct nouveau_pm *pm = nouveau_pm(dev); 54 struct nouveau_pm *pm = nouveau_pm(dev);
55 struct nouveau_therm *therm = nouveau_therm(drm);
122 int ret; 56 int ret;
123 57
124 /*XXX: not on all boards, we should control based on temperature 58 /*XXX: not on all boards, we should control based on temperature
125 * on recent boards.. or maybe on some other factor we don't 59 * on recent boards.. or maybe on some other factor we don't
126 * know about? 60 * know about?
127 */ 61 */
128 if (a->fanspeed && b->fanspeed && b->fanspeed > a->fanspeed) { 62 if (therm && therm->fan_set &&
129 ret = nouveau_pwmfan_set(dev, perflvl->fanspeed); 63 a->fanspeed && b->fanspeed && b->fanspeed > a->fanspeed) {
64 ret = therm->fan_set(therm, perflvl->fanspeed);
130 if (ret && ret != -ENODEV) { 65 if (ret && ret != -ENODEV) {
131 NV_ERROR(drm, "fanspeed set failed: %d\n", ret); 66 NV_ERROR(drm, "fanspeed set failed: %d\n", ret);
132 return ret; 67 return ret;
@@ -291,7 +226,9 @@ const struct nouveau_pm_profile_func nouveau_pm_static_profile_func = {
291static int 226static int
292nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) 227nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
293{ 228{
229 struct nouveau_drm *drm = nouveau_drm(dev);
294 struct nouveau_pm *pm = nouveau_pm(dev); 230 struct nouveau_pm *pm = nouveau_pm(dev);
231 struct nouveau_therm *therm = nouveau_therm(drm->device);
295 int ret; 232 int ret;
296 233
297 memset(perflvl, 0, sizeof(*perflvl)); 234 memset(perflvl, 0, sizeof(*perflvl));
@@ -310,9 +247,11 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
310 } 247 }
311 } 248 }
312 249
313 ret = nouveau_pwmfan_get(dev); 250 if (therm && therm->fan_get) {
314 if (ret > 0) 251 ret = therm->fan_get(therm);
315 perflvl->fanspeed = ret; 252 if (ret >= 0)
253 perflvl->fanspeed = ret;
254 }
316 255
317 nouveau_mem_timing_read(dev, &perflvl->timing); 256 nouveau_mem_timing_read(dev, &perflvl->timing);
318 return 0; 257 return 0;
@@ -462,9 +401,10 @@ static ssize_t
462nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) 401nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
463{ 402{
464 struct drm_device *dev = dev_get_drvdata(d); 403 struct drm_device *dev = dev_get_drvdata(d);
465 struct nouveau_pm *pm = nouveau_pm(dev); 404 struct nouveau_drm *drm = nouveau_drm(dev);
405 struct nouveau_therm *therm = nouveau_therm(drm->device);
466 406
467 return snprintf(buf, PAGE_SIZE, "%d\n", pm->temp_get(dev)*1000); 407 return snprintf(buf, PAGE_SIZE, "%d\n", therm->temp_get(therm) * 1000);
468} 408}
469static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp, 409static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp,
470 NULL, 0); 410 NULL, 0);
@@ -473,26 +413,25 @@ static ssize_t
473nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf) 413nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf)
474{ 414{
475 struct drm_device *dev = dev_get_drvdata(d); 415 struct drm_device *dev = dev_get_drvdata(d);
476 struct nouveau_pm *pm = nouveau_pm(dev); 416 struct nouveau_drm *drm = nouveau_drm(dev);
477 struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 417 struct nouveau_therm *therm = nouveau_therm(drm->device);
478 418
479 return snprintf(buf, PAGE_SIZE, "%d\n", temp->down_clock*1000); 419 return snprintf(buf, PAGE_SIZE, "%d\n",
420 therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK) * 1000);
480} 421}
481static ssize_t 422static ssize_t
482nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a, 423nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a,
483 const char *buf, size_t count) 424 const char *buf, size_t count)
484{ 425{
485 struct drm_device *dev = dev_get_drvdata(d); 426 struct drm_device *dev = dev_get_drvdata(d);
486 struct nouveau_pm *pm = nouveau_pm(dev); 427 struct nouveau_drm *drm = nouveau_drm(dev);
487 struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 428 struct nouveau_therm *therm = nouveau_therm(drm->device);
488 long value; 429 long value;
489 430
490 if (kstrtol(buf, 10, &value) == -EINVAL) 431 if (kstrtol(buf, 10, &value) == -EINVAL)
491 return count; 432 return count;
492 433
493 temp->down_clock = value/1000; 434 therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK, value / 1000);
494
495 nouveau_temp_safety_checks(dev);
496 435
497 return count; 436 return count;
498} 437}
@@ -505,10 +444,11 @@ nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a,
505 char *buf) 444 char *buf)
506{ 445{
507 struct drm_device *dev = dev_get_drvdata(d); 446 struct drm_device *dev = dev_get_drvdata(d);
508 struct nouveau_pm *pm = nouveau_pm(dev); 447 struct nouveau_drm *drm = nouveau_drm(dev);
509 struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 448 struct nouveau_therm *therm = nouveau_therm(drm->device);
510 449
511 return snprintf(buf, PAGE_SIZE, "%d\n", temp->critical*1000); 450 return snprintf(buf, PAGE_SIZE, "%d\n",
451 therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL) * 1000);
512} 452}
513static ssize_t 453static ssize_t
514nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a, 454nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a,
@@ -516,16 +456,14 @@ nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a,
516 size_t count) 456 size_t count)
517{ 457{
518 struct drm_device *dev = dev_get_drvdata(d); 458 struct drm_device *dev = dev_get_drvdata(d);
519 struct nouveau_pm *pm = nouveau_pm(dev); 459 struct nouveau_drm *drm = nouveau_drm(dev);
520 struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 460 struct nouveau_therm *therm = nouveau_therm(drm->device);
521 long value; 461 long value;
522 462
523 if (kstrtol(buf, 10, &value) == -EINVAL) 463 if (kstrtol(buf, 10, &value) == -EINVAL)
524 return count; 464 return count;
525 465
526 temp->critical = value/1000; 466 therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL, value / 1000);
527
528 nouveau_temp_safety_checks(dev);
529 467
530 return count; 468 return count;
531} 469}
@@ -558,34 +496,9 @@ nouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr,
558{ 496{
559 struct drm_device *dev = dev_get_drvdata(d); 497 struct drm_device *dev = dev_get_drvdata(d);
560 struct nouveau_drm *drm = nouveau_drm(dev); 498 struct nouveau_drm *drm = nouveau_drm(dev);
561 struct nouveau_timer *ptimer = nouveau_timer(drm->device); 499 struct nouveau_therm *therm = nouveau_therm(drm->device);
562 struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
563 struct dcb_gpio_func func;
564 u32 cycles, cur, prev;
565 u64 start;
566
567 if (gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &func))
568 return -ENODEV;
569
570 /* Monitor the GPIO input 0x3b for 250ms.
571 * When the fan spins, it changes the value of GPIO FAN_SENSE.
572 * We get 4 changes (0 -> 1 -> 0 -> 1 -> [...]) per complete rotation.
573 */
574 start = ptimer->read(ptimer);
575 prev = gpio->get(gpio, 0, func.func, func.line);
576 cycles = 0;
577 do {
578 cur = gpio->get(gpio, 0, func.func, func.line);
579 if (prev != cur) {
580 cycles++;
581 prev = cur;
582 }
583 500
584 usleep_range(500, 1000); /* supports 0 < rpm < 7500 */ 501 return snprintf(buf, PAGE_SIZE, "%d\n", therm->fan_sense(therm));
585 } while (ptimer->read(ptimer) - start < 250000000);
586
587 /* interpolate to get rpm */
588 return sprintf(buf, "%i\n", cycles / 4 * 4 * 60);
589} 502}
590static SENSOR_DEVICE_ATTR(fan0_input, S_IRUGO, nouveau_hwmon_show_fan0_input, 503static SENSOR_DEVICE_ATTR(fan0_input, S_IRUGO, nouveau_hwmon_show_fan0_input,
591 NULL, 0); 504 NULL, 0);
@@ -594,9 +507,11 @@ static ssize_t
594nouveau_hwmon_get_pwm0(struct device *d, struct device_attribute *a, char *buf) 507nouveau_hwmon_get_pwm0(struct device *d, struct device_attribute *a, char *buf)
595{ 508{
596 struct drm_device *dev = dev_get_drvdata(d); 509 struct drm_device *dev = dev_get_drvdata(d);
510 struct nouveau_drm *drm = nouveau_drm(dev);
511 struct nouveau_therm *therm = nouveau_therm(drm->device);
597 int ret; 512 int ret;
598 513
599 ret = nouveau_pwmfan_get(dev); 514 ret = therm->fan_get(therm);
600 if (ret < 0) 515 if (ret < 0)
601 return ret; 516 return ret;
602 517
@@ -608,7 +523,8 @@ nouveau_hwmon_set_pwm0(struct device *d, struct device_attribute *a,
608 const char *buf, size_t count) 523 const char *buf, size_t count)
609{ 524{
610 struct drm_device *dev = dev_get_drvdata(d); 525 struct drm_device *dev = dev_get_drvdata(d);
611 struct nouveau_pm *pm = nouveau_pm(dev); 526 struct nouveau_drm *drm = nouveau_drm(dev);
527 struct nouveau_therm *therm = nouveau_therm(drm->device);
612 int ret = -ENODEV; 528 int ret = -ENODEV;
613 long value; 529 long value;
614 530
@@ -618,12 +534,7 @@ nouveau_hwmon_set_pwm0(struct device *d, struct device_attribute *a,
618 if (kstrtol(buf, 10, &value) == -EINVAL) 534 if (kstrtol(buf, 10, &value) == -EINVAL)
619 return -EINVAL; 535 return -EINVAL;
620 536
621 if (value < pm->fan.min_duty) 537 ret = therm->fan_set(therm, value);
622 value = pm->fan.min_duty;
623 if (value > pm->fan.max_duty)
624 value = pm->fan.max_duty;
625
626 ret = nouveau_pwmfan_set(dev, value);
627 if (ret) 538 if (ret)
628 return ret; 539 return ret;
629 540
@@ -639,9 +550,15 @@ nouveau_hwmon_get_pwm0_min(struct device *d,
639 struct device_attribute *a, char *buf) 550 struct device_attribute *a, char *buf)
640{ 551{
641 struct drm_device *dev = dev_get_drvdata(d); 552 struct drm_device *dev = dev_get_drvdata(d);
642 struct nouveau_pm *pm = nouveau_pm(dev); 553 struct nouveau_drm *drm = nouveau_drm(dev);
554 struct nouveau_therm *therm = nouveau_therm(drm->device);
555 int ret;
556
557 ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY);
558 if (ret < 0)
559 return ret;
643 560
644 return sprintf(buf, "%i\n", pm->fan.min_duty); 561 return sprintf(buf, "%i\n", ret);
645} 562}
646 563
647static ssize_t 564static ssize_t
@@ -649,22 +566,17 @@ nouveau_hwmon_set_pwm0_min(struct device *d, struct device_attribute *a,
649 const char *buf, size_t count) 566 const char *buf, size_t count)
650{ 567{
651 struct drm_device *dev = dev_get_drvdata(d); 568 struct drm_device *dev = dev_get_drvdata(d);
652 struct nouveau_pm *pm = nouveau_pm(dev); 569 struct nouveau_drm *drm = nouveau_drm(dev);
570 struct nouveau_therm *therm = nouveau_therm(drm->device);
653 long value; 571 long value;
572 int ret;
654 573
655 if (kstrtol(buf, 10, &value) == -EINVAL) 574 if (kstrtol(buf, 10, &value) == -EINVAL)
656 return -EINVAL; 575 return -EINVAL;
657 576
658 if (value < 0) 577 ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY, value);
659 value = 0; 578 if (ret < 0)
660 579 return ret;
661 if (pm->fan.max_duty - value < 10)
662 value = pm->fan.max_duty - 10;
663
664 if (value < 10)
665 pm->fan.min_duty = 10;
666 else
667 pm->fan.min_duty = value;
668 580
669 return count; 581 return count;
670} 582}
@@ -678,9 +590,15 @@ nouveau_hwmon_get_pwm0_max(struct device *d,
678 struct device_attribute *a, char *buf) 590 struct device_attribute *a, char *buf)
679{ 591{
680 struct drm_device *dev = dev_get_drvdata(d); 592 struct drm_device *dev = dev_get_drvdata(d);
681 struct nouveau_pm *pm = nouveau_pm(dev); 593 struct nouveau_drm *drm = nouveau_drm(dev);
594 struct nouveau_therm *therm = nouveau_therm(drm->device);
595 int ret;
682 596
683 return sprintf(buf, "%i\n", pm->fan.max_duty); 597 ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY);
598 if (ret < 0)
599 return ret;
600
601 return sprintf(buf, "%i\n", ret);
684} 602}
685 603
686static ssize_t 604static ssize_t
@@ -688,22 +606,17 @@ nouveau_hwmon_set_pwm0_max(struct device *d, struct device_attribute *a,
688 const char *buf, size_t count) 606 const char *buf, size_t count)
689{ 607{
690 struct drm_device *dev = dev_get_drvdata(d); 608 struct drm_device *dev = dev_get_drvdata(d);
691 struct nouveau_pm *pm = nouveau_pm(dev); 609 struct nouveau_drm *drm = nouveau_drm(dev);
610 struct nouveau_therm *therm = nouveau_therm(drm->device);
692 long value; 611 long value;
612 int ret;
693 613
694 if (kstrtol(buf, 10, &value) == -EINVAL) 614 if (kstrtol(buf, 10, &value) == -EINVAL)
695 return -EINVAL; 615 return -EINVAL;
696 616
697 if (value < 0) 617 ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY, value);
698 value = 0; 618 if (ret < 0)
699 619 return ret;
700 if (value - pm->fan.min_duty < 10)
701 value = pm->fan.min_duty + 10;
702
703 if (value > 100)
704 pm->fan.max_duty = 100;
705 else
706 pm->fan.max_duty = value;
707 620
708 return count; 621 return count;
709} 622}
@@ -747,14 +660,14 @@ nouveau_hwmon_init(struct drm_device *dev)
747{ 660{
748 struct nouveau_pm *pm = nouveau_pm(dev); 661 struct nouveau_pm *pm = nouveau_pm(dev);
749 struct nouveau_drm *drm = nouveau_drm(dev); 662 struct nouveau_drm *drm = nouveau_drm(dev);
750 struct nouveau_gpio *gpio = nouveau_gpio(drm->device); 663 struct nouveau_therm *therm = nouveau_therm(drm->device);
751 struct dcb_gpio_func func;
752 664
753#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) 665#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
754 struct device *hwmon_dev; 666 struct device *hwmon_dev;
755 int ret = 0; 667 int ret = 0;
756 668
757 if (!pm->temp_get) 669 if (!therm || !therm->temp_get || !therm->attr_get ||
670 !therm->attr_set || therm->temp_get(therm) < 0)
758 return -ENODEV; 671 return -ENODEV;
759 672
760 hwmon_dev = hwmon_device_register(&dev->pdev->dev); 673 hwmon_dev = hwmon_device_register(&dev->pdev->dev);
@@ -776,7 +689,7 @@ nouveau_hwmon_init(struct drm_device *dev)
776 /*XXX: incorrect, need better detection for this, some boards have 689 /*XXX: incorrect, need better detection for this, some boards have
777 * the gpio entries for pwm fan control even when there's no 690 * the gpio entries for pwm fan control even when there's no
778 * actual fan connected to it... therm table? */ 691 * actual fan connected to it... therm table? */
779 if (nouveau_pwmfan_get(dev) >= 0) { 692 if (therm->fan_get && therm->fan_get(therm) >= 0) {
780 ret = sysfs_create_group(&dev->pdev->dev.kobj, 693 ret = sysfs_create_group(&dev->pdev->dev.kobj,
781 &hwmon_pwm_fan_attrgroup); 694 &hwmon_pwm_fan_attrgroup);
782 if (ret) 695 if (ret)
@@ -784,7 +697,7 @@ nouveau_hwmon_init(struct drm_device *dev)
784 } 697 }
785 698
786 /* if the card can read the fan rpm */ 699 /* if the card can read the fan rpm */
787 if (!gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &func)) { 700 if (therm->fan_sense(therm) >= 0) {
788 ret = sysfs_create_group(&dev->pdev->dev.kobj, 701 ret = sysfs_create_group(&dev->pdev->dev.kobj,
789 &hwmon_fan_rpm_attrgroup); 702 &hwmon_fan_rpm_attrgroup);
790 if (ret) 703 if (ret)
@@ -873,9 +786,6 @@ nouveau_pm_init(struct drm_device *dev)
873 pm->clocks_set = nv40_pm_clocks_set; 786 pm->clocks_set = nv40_pm_clocks_set;
874 pm->voltage_get = nouveau_voltage_gpio_get; 787 pm->voltage_get = nouveau_voltage_gpio_get;
875 pm->voltage_set = nouveau_voltage_gpio_set; 788 pm->voltage_set = nouveau_voltage_gpio_set;
876 pm->temp_get = nv40_temp_get;
877 pm->pwm_get = nv40_pm_pwm_get;
878 pm->pwm_set = nv40_pm_pwm_set;
879 } else 789 } else
880 if (device->card_type < NV_C0) { 790 if (device->card_type < NV_C0) {
881 if (device->chipset < 0xa3 || 791 if (device->chipset < 0xa3 ||
@@ -891,9 +801,6 @@ nouveau_pm_init(struct drm_device *dev)
891 } 801 }
892 pm->voltage_get = nouveau_voltage_gpio_get; 802 pm->voltage_get = nouveau_voltage_gpio_get;
893 pm->voltage_set = nouveau_voltage_gpio_set; 803 pm->voltage_set = nouveau_voltage_gpio_set;
894 pm->temp_get = nv84_temp_get;
895 pm->pwm_get = nv50_pm_pwm_get;
896 pm->pwm_set = nv50_pm_pwm_set;
897 } else 804 } else
898 if (device->card_type < NV_E0) { 805 if (device->card_type < NV_E0) {
899 pm->clocks_get = nvc0_pm_clocks_get; 806 pm->clocks_get = nvc0_pm_clocks_get;
@@ -901,17 +808,11 @@ nouveau_pm_init(struct drm_device *dev)
901 pm->clocks_set = nvc0_pm_clocks_set; 808 pm->clocks_set = nvc0_pm_clocks_set;
902 pm->voltage_get = nouveau_voltage_gpio_get; 809 pm->voltage_get = nouveau_voltage_gpio_get;
903 pm->voltage_set = nouveau_voltage_gpio_set; 810 pm->voltage_set = nouveau_voltage_gpio_set;
904 pm->temp_get = nv84_temp_get;
905 if (device->card_type < NV_D0) {
906 pm->pwm_get = nv50_pm_pwm_get;
907 pm->pwm_set = nv50_pm_pwm_set;
908 }
909 } 811 }
910 812
911 813
912 /* parse aux tables from vbios */ 814 /* parse aux tables from vbios */
913 nouveau_volt_init(dev); 815 nouveau_volt_init(dev);
914 nouveau_temp_init(dev);
915 816
916 INIT_LIST_HEAD(&pm->profiles); 817 INIT_LIST_HEAD(&pm->profiles);
917 818
@@ -950,9 +851,6 @@ nouveau_pm_init(struct drm_device *dev)
950 if (nouveau_perflvl != NULL) 851 if (nouveau_perflvl != NULL)
951 nouveau_pm_profile_set(dev, nouveau_perflvl); 852 nouveau_pm_profile_set(dev, nouveau_perflvl);
952 853
953 /* determine the current fan speed */
954 pm->fan.percent = nouveau_pwmfan_get(dev);
955
956 nouveau_sysfs_init(dev); 854 nouveau_sysfs_init(dev);
957 nouveau_hwmon_init(dev); 855 nouveau_hwmon_init(dev);
958#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) 856#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
@@ -977,7 +875,6 @@ nouveau_pm_fini(struct drm_device *dev)
977 if (pm->cur != &pm->boot) 875 if (pm->cur != &pm->boot)
978 nouveau_pm_perflvl_set(dev, &pm->boot); 876 nouveau_pm_perflvl_set(dev, &pm->boot);
979 877
980 nouveau_temp_fini(dev);
981 nouveau_perf_fini(dev); 878 nouveau_perf_fini(dev);
982 nouveau_volt_fini(dev); 879 nouveau_volt_fini(dev);
983 880
@@ -1003,5 +900,4 @@ nouveau_pm_resume(struct drm_device *dev)
1003 perflvl = pm->cur; 900 perflvl = pm->cur;
1004 pm->cur = &pm->boot; 901 pm->cur = &pm->boot;
1005 nouveau_pm_perflvl_set(dev, perflvl); 902 nouveau_pm_perflvl_set(dev, perflvl);
1006 nouveau_pwmfan_set(dev, pm->fan.percent);
1007} 903}
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h
index 2e39ccbd5d4..73b789c230a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.h
@@ -150,14 +150,6 @@ struct nouveau_pm_threshold_temp {
150 s16 down_clock; 150 s16 down_clock;
151}; 151};
152 152
153struct nouveau_pm_fan {
154 u32 percent;
155 u32 min_duty;
156 u32 max_duty;
157 u32 pwm_freq;
158 u32 pwm_divisor;
159};
160
161struct nouveau_pm { 153struct nouveau_pm {
162 struct drm_device *dev; 154 struct drm_device *dev;
163 155
@@ -166,7 +158,6 @@ struct nouveau_pm {
166 int nr_perflvl; 158 int nr_perflvl;
167 struct nouveau_pm_temp_sensor_constants sensor_constants; 159 struct nouveau_pm_temp_sensor_constants sensor_constants;
168 struct nouveau_pm_threshold_temp threshold_temp; 160 struct nouveau_pm_threshold_temp threshold_temp;
169 struct nouveau_pm_fan fan;
170 161
171 struct nouveau_pm_profile *profile_ac; 162 struct nouveau_pm_profile *profile_ac;
172 struct nouveau_pm_profile *profile_dc; 163 struct nouveau_pm_profile *profile_dc;
@@ -185,9 +176,6 @@ struct nouveau_pm {
185 176
186 int (*voltage_get)(struct drm_device *); 177 int (*voltage_get)(struct drm_device *);
187 int (*voltage_set)(struct drm_device *, int voltage); 178 int (*voltage_set)(struct drm_device *, int voltage);
188 int (*pwm_get)(struct drm_device *, int line, u32*, u32*);
189 int (*pwm_set)(struct drm_device *, int line, u32, u32);
190 int (*temp_get)(struct drm_device *);
191}; 179};
192 180
193static inline struct nouveau_pm * 181static inline struct nouveau_pm *
@@ -270,13 +258,6 @@ int nvc0_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *);
270void *nvc0_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *); 258void *nvc0_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *);
271int nvc0_pm_clocks_set(struct drm_device *, void *); 259int nvc0_pm_clocks_set(struct drm_device *, void *);
272 260
273/* nouveau_temp.c */
274void nouveau_temp_init(struct drm_device *dev);
275void nouveau_temp_fini(struct drm_device *dev);
276void nouveau_temp_safety_checks(struct drm_device *dev);
277int nv40_temp_get(struct drm_device *dev);
278int nv84_temp_get(struct drm_device *dev);
279
280/* nouveau_mem.c */ 261/* nouveau_mem.c */
281int nouveau_mem_timing_calc(struct drm_device *, u32 freq, 262int nouveau_mem_timing_calc(struct drm_device *, u32 freq,
282 struct nouveau_pm_memtiming *); 263 struct nouveau_pm_memtiming *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_temp.c b/drivers/gpu/drm/nouveau/nouveau_temp.c
deleted file mode 100644
index 6d2b957ca01..00000000000
--- 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}
diff --git a/drivers/gpu/drm/nouveau/nv40_pm.c b/drivers/gpu/drm/nouveau/nv40_pm.c
index 23f200630d8..e9b81a97c48 100644
--- a/drivers/gpu/drm/nouveau/nv40_pm.c
+++ b/drivers/gpu/drm/nouveau/nv40_pm.c
@@ -351,52 +351,3 @@ resume:
351 kfree(info); 351 kfree(info);
352 return ret; 352 return ret;
353} 353}
354
355int
356nv40_pm_pwm_get(struct drm_device *dev, int line, u32 *divs, u32 *duty)
357{
358 struct nouveau_drm *drm = nouveau_drm(dev);
359 struct nouveau_device *device = nouveau_dev(dev);
360
361 if (line == 2) {
362 u32 reg = nv_rd32(device, 0x0010f0);
363 if (reg & 0x80000000) {
364 *duty = (reg & 0x7fff0000) >> 16;
365 *divs = (reg & 0x00007fff);
366 return 0;
367 }
368 } else
369 if (line == 9) {
370 u32 reg = nv_rd32(device, 0x0015f4);
371 if (reg & 0x80000000) {
372 *divs = nv_rd32(device, 0x0015f8);
373 *duty = (reg & 0x7fffffff);
374 return 0;
375 }
376 } else {
377 NV_ERROR(drm, "unknown pwm ctrl for gpio %d\n", line);
378 return -ENODEV;
379 }
380
381 return -EINVAL;
382}
383
384int
385nv40_pm_pwm_set(struct drm_device *dev, int line, u32 divs, u32 duty)
386{
387 struct nouveau_device *device = nouveau_dev(dev);
388 struct nouveau_drm *drm = nouveau_drm(dev);
389
390 if (line == 2) {
391 nv_wr32(device, 0x0010f0, 0x80000000 | (duty << 16) | divs);
392 } else
393 if (line == 9) {
394 nv_wr32(device, 0x0015f8, divs);
395 nv_wr32(device, 0x0015f4, duty | 0x80000000);
396 } else {
397 NV_ERROR(drm, "unknown pwm ctrl for gpio %d\n", line);
398 return -ENODEV;
399 }
400
401 return 0;
402}
diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c
index 0036c8c966d..7724eae5db9 100644
--- a/drivers/gpu/drm/nouveau/nv50_pm.c
+++ b/drivers/gpu/drm/nouveau/nv50_pm.c
@@ -853,61 +853,3 @@ resume:
853 kfree(info); 853 kfree(info);
854 return ret; 854 return ret;
855} 855}
856
857static int
858pwm_info(struct drm_device *dev, int *line, int *ctrl, int *indx)
859{
860 struct nouveau_drm *drm = nouveau_drm(dev);
861
862 if (*line == 0x04) {
863 *ctrl = 0x00e100;
864 *line = 4;
865 *indx = 0;
866 } else
867 if (*line == 0x09) {
868 *ctrl = 0x00e100;
869 *line = 9;
870 *indx = 1;
871 } else
872 if (*line == 0x10) {
873 *ctrl = 0x00e28c;
874 *line = 0;
875 *indx = 0;
876 } else {
877 NV_ERROR(drm, "unknown pwm ctrl for gpio %d\n", *line);
878 return -ENODEV;
879 }
880
881 return 0;
882}
883
884int
885nv50_pm_pwm_get(struct drm_device *dev, int line, u32 *divs, u32 *duty)
886{
887 struct nouveau_device *device = nouveau_dev(dev);
888 int ctrl, id, ret = pwm_info(dev, &line, &ctrl, &id);
889 if (ret)
890 return ret;
891
892 if (nv_rd32(device, ctrl) & (1 << line)) {
893 *divs = nv_rd32(device, 0x00e114 + (id * 8));
894 *duty = nv_rd32(device, 0x00e118 + (id * 8));
895 return 0;
896 }
897
898 return -EINVAL;
899}
900
901int
902nv50_pm_pwm_set(struct drm_device *dev, int line, u32 divs, u32 duty)
903{
904 struct nouveau_device *device = nouveau_dev(dev);
905 int ctrl, id, ret = pwm_info(dev, &line, &ctrl, &id);
906 if (ret)
907 return ret;
908
909 nv_mask(device, ctrl, 0x00010001 << line, 0x00000001 << line);
910 nv_wr32(device, 0x00e114 + (id * 8), divs);
911 nv_wr32(device, 0x00e118 + (id * 8), duty | 0x80000000);
912 return 0;
913}