1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include "priv.h"
26
27enum nv40_sensor_style { INVALID_STYLE = -1, OLD_STYLE = 0, NEW_STYLE = 1 };
28
29static enum nv40_sensor_style
30nv40_sensor_style(struct nvkm_therm *therm)
31{
32 switch (therm->subdev.device->chipset) {
33 case 0x43:
34 case 0x44:
35 case 0x4a:
36 case 0x47:
37 return OLD_STYLE;
38 case 0x46:
39 case 0x49:
40 case 0x4b:
41 case 0x4e:
42 case 0x4c:
43 case 0x67:
44 case 0x68:
45 case 0x63:
46 return NEW_STYLE;
47 default:
48 return INVALID_STYLE;
49 }
50}
51
52static int
53nv40_sensor_setup(struct nvkm_therm *therm)
54{
55 struct nvkm_device *device = therm->subdev.device;
56 enum nv40_sensor_style style = nv40_sensor_style(therm);
57
58
59 if (style == NEW_STYLE) {
60 nvkm_mask(device, 0x15b8, 0x80000000, 0);
61 nvkm_wr32(device, 0x15b0, 0x80003fff);
62 mdelay(20);
63 return nvkm_rd32(device, 0x15b4) & 0x3fff;
64 } else if (style == OLD_STYLE) {
65 nvkm_wr32(device, 0x15b0, 0xff);
66 mdelay(20);
67 return nvkm_rd32(device, 0x15b4) & 0xff;
68 } else
69 return -ENODEV;
70}
71
72static int
73nv40_temp_get(struct nvkm_therm *therm)
74{
75 struct nvkm_device *device = therm->subdev.device;
76 struct nvbios_therm_sensor *sensor = &therm->bios_sensor;
77 enum nv40_sensor_style style = nv40_sensor_style(therm);
78 int core_temp;
79
80 if (style == NEW_STYLE) {
81 nvkm_wr32(device, 0x15b0, 0x80003fff);
82 core_temp = nvkm_rd32(device, 0x15b4) & 0x3fff;
83 } else if (style == OLD_STYLE) {
84 nvkm_wr32(device, 0x15b0, 0xff);
85 core_temp = nvkm_rd32(device, 0x15b4) & 0xff;
86 } else
87 return -ENODEV;
88
89
90 if (!sensor->slope_div || !sensor->slope_mult ||
91 !sensor->offset_num || !sensor->offset_den)
92 return -ENODEV;
93
94 core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
95 core_temp = core_temp + sensor->offset_num / sensor->offset_den;
96 core_temp = core_temp + sensor->offset_constant - 8;
97
98
99 if (core_temp < 0)
100 core_temp = 0;
101
102 return core_temp;
103}
104
105static int
106nv40_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable)
107{
108 struct nvkm_subdev *subdev = &therm->subdev;
109 struct nvkm_device *device = subdev->device;
110 u32 mask = enable ? 0x80000000 : 0x00000000;
111 if (line == 2) nvkm_mask(device, 0x0010f0, 0x80000000, mask);
112 else if (line == 9) nvkm_mask(device, 0x0015f4, 0x80000000, mask);
113 else {
114 nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", line);
115 return -ENODEV;
116 }
117 return 0;
118}
119
120static int
121nv40_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty)
122{
123 struct nvkm_subdev *subdev = &therm->subdev;
124 struct nvkm_device *device = subdev->device;
125 if (line == 2) {
126 u32 reg = nvkm_rd32(device, 0x0010f0);
127 if (reg & 0x80000000) {
128 *duty = (reg & 0x7fff0000) >> 16;
129 *divs = (reg & 0x00007fff);
130 return 0;
131 }
132 } else
133 if (line == 9) {
134 u32 reg = nvkm_rd32(device, 0x0015f4);
135 if (reg & 0x80000000) {
136 *divs = nvkm_rd32(device, 0x0015f8);
137 *duty = (reg & 0x7fffffff);
138 return 0;
139 }
140 } else {
141 nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", line);
142 return -ENODEV;
143 }
144
145 return -EINVAL;
146}
147
148static int
149nv40_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty)
150{
151 struct nvkm_subdev *subdev = &therm->subdev;
152 struct nvkm_device *device = subdev->device;
153 if (line == 2) {
154 nvkm_mask(device, 0x0010f0, 0x7fff7fff, (duty << 16) | divs);
155 } else
156 if (line == 9) {
157 nvkm_wr32(device, 0x0015f8, divs);
158 nvkm_mask(device, 0x0015f4, 0x7fffffff, duty);
159 } else {
160 nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", line);
161 return -ENODEV;
162 }
163
164 return 0;
165}
166
167void
168nv40_therm_intr(struct nvkm_therm *therm)
169{
170 struct nvkm_subdev *subdev = &therm->subdev;
171 struct nvkm_device *device = subdev->device;
172 uint32_t stat = nvkm_rd32(device, 0x1100);
173
174
175
176
177 nvkm_wr32(device, 0x1100, 0x70000);
178
179 nvkm_error(subdev, "THERM received an IRQ: stat = %x\n", stat);
180}
181
182static void
183nv40_therm_init(struct nvkm_therm *therm)
184{
185 nv40_sensor_setup(therm);
186}
187
188static const struct nvkm_therm_func
189nv40_therm = {
190 .init = nv40_therm_init,
191 .intr = nv40_therm_intr,
192 .pwm_ctrl = nv40_fan_pwm_ctrl,
193 .pwm_get = nv40_fan_pwm_get,
194 .pwm_set = nv40_fan_pwm_set,
195 .temp_get = nv40_temp_get,
196 .program_alarms = nvkm_therm_program_alarms_polling,
197};
198
199int
200nv40_therm_new(struct nvkm_device *device, int index,
201 struct nvkm_therm **ptherm)
202{
203 return nvkm_therm_new_(&nv40_therm, device, index, ptherm);
204}
205