xref: /openbsd/sys/dev/pci/itherm.c (revision 3bef86f7)
1 /*
2  * Copyright (c) 2010 Mike Larkin <mlarkin@openbsd.org>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /*
18  * Intel 3400 thermal sensor controller driver
19  */
20 
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/device.h>
24 #include <sys/sensors.h>
25 
26 #include <dev/pci/pcireg.h>
27 #include <dev/pci/pcivar.h>
28 #include <dev/pci/pcidevs.h>
29 
30 /*
31  * Intel 5 series (3400) Thermal Sensor Data
32  * See Intel document 322169-004 (January 2012)
33  */
34 #define	ITHERM_NUM_SENSORS		12
35 #define	ITHERM_SENSOR_THERMOMETER	0
36 #define	ITHERM_SENSOR_CORETEMP1		1
37 #define	ITHERM_SENSOR_CORETEMP2		2
38 #define	ITHERM_SENSOR_COREENERGY	3
39 #define	ITHERM_SENSOR_GPUTEMP		4
40 #define	ITHERM_SENSOR_MAXPROCTEMP	5
41 #define	ITHERM_SENSOR_DIMMTEMP1		6
42 #define	ITHERM_SENSOR_DIMMTEMP2		7
43 #define	ITHERM_SENSOR_DIMMTEMP3		8
44 #define	ITHERM_SENSOR_DIMMTEMP4		9
45 #define	ITHERM_SENSOR_GPUTEMP_ABSOLUTE	10
46 #define	ITHERM_SENSOR_PCHTEMP_ABSOLUTE	11
47 
48 /* Section 22.2 of datasheet */
49 #define	ITHERM_TSE	0x1	/* TS enable */
50 #define	ITHERM_TSTR	0x3	/* TS thermometer read */
51 #define	ITHERM_TRC	0x1A	/* TS reporting control */
52 #define	ITHERM_CTV1	0x30	/* TS core temp value 1 */
53 #define	ITHERM_CTV2	0x32	/* TS core temp value 2 */
54 #define	ITHERM_CEV1	0x34	/* TS core energy value 1 */
55 #define	ITHERM_MGTV	0x58	/* mem/GPU temp value */
56 #define	ITHERM_PTV	0x60	/* TS CPU temp value */
57 #define	ITHERM_DTV	0xAC	/* DIMM temp values */
58 #define	ITHERM_ITV	0xD8	/* Internal temp values */
59 
60 #define	ITHERM_TEMP_READ_ENABLE		0xFF
61 #define	ITHERM_TDR_ENABLE		0x1000
62 #define	ITHERM_SECOND_CORE_ENABLE	0x8000
63 
64 #define	ITHERM_TSE_ENABLE	0xB8	/* magic number in datasheet */
65 
66 #define	ITHERM_CTV_INVALID	0x8000
67 #define	ITHERM_CTV_INT_MASK	0x3FC0	/* higher 8 bits */
68 #define	ITHERM_CTV_FRAC_MASK	0x003F	/* lower 6 bits */
69 
70 #define	ITHERM_REFRESH_INTERVAL 5
71 
72 struct itherm_softc {
73 	struct device		sc_dev;
74 
75 	bus_addr_t		sc_addr;
76 	bus_space_tag_t		iot;
77 	bus_space_handle_t	ioh;
78 	bus_size_t		size;
79 
80 	int64_t			energy_prev;
81 
82 	struct ksensor sensors[ITHERM_NUM_SENSORS];
83 	struct ksensordev sensordev;
84 	void (*refresh_sensor_data)(struct itherm_softc *);
85 };
86 
87 #define IREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (a))
88 #define IREAD2(sc, a) bus_space_read_2((sc)->iot, (sc)->ioh, (a))
89 #define IREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (a))
90 #define IWRITE1(sc, a, x) bus_space_write_1((sc)->iot, (sc)->ioh, (a), (x))
91 #define IWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (a), (x))
92 
93 int  itherm_probe(struct device *, void *, void *);
94 void itherm_attach(struct device *, struct device *, void *);
95 void itherm_refresh(void *);
96 void itherm_enable(struct itherm_softc *);
97 void itherm_refresh_sensor_data(struct itherm_softc *);
98 int  itherm_activate(struct device *, int);
99 void itherm_bias_temperature_sensor(struct ksensor *);
100 
101 const struct pci_matchid itherm_devices[] = {
102 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_3400_THERMAL }
103 };
104 
105 struct cfdriver itherm_cd = {
106 	NULL, "itherm", DV_DULL
107 };
108 
109 const struct cfattach itherm_ca = {
110 	sizeof(struct itherm_softc), itherm_probe, itherm_attach, NULL,
111 	itherm_activate
112 };
113 
114 int
115 itherm_probe(struct device *parent, void *match, void *aux)
116 {
117 	return (pci_matchbyid((struct pci_attach_args *)aux, itherm_devices,
118 	    sizeof(itherm_devices)/sizeof(itherm_devices[0])));
119 }
120 
121 void
122 itherm_attach(struct device *parent, struct device *self, void *aux)
123 {
124 	struct itherm_softc *sc = (struct itherm_softc *)self;
125 	struct pci_attach_args *pa = aux;
126 	int i;
127 	pcireg_t v;
128 
129 	v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START);
130 	v &= PCI_MAPREG_TYPE_MASK | PCI_MAPREG_MEM_TYPE_MASK;
131 	if (pci_mapreg_map(pa, PCI_MAPREG_START,
132 	    v, 0, &sc->iot, &sc->ioh, NULL, &sc->size, 0)) {
133 		printf(": can't map mem space\n");
134 		return;
135 	}
136 
137 	sc->sensors[ITHERM_SENSOR_THERMOMETER].type = SENSOR_TEMP;
138 	sc->sensors[ITHERM_SENSOR_CORETEMP1].type = SENSOR_TEMP;
139 	sc->sensors[ITHERM_SENSOR_CORETEMP2].type = SENSOR_TEMP;
140 	sc->sensors[ITHERM_SENSOR_COREENERGY].type = SENSOR_WATTS;
141 	sc->sensors[ITHERM_SENSOR_GPUTEMP].type = SENSOR_TEMP;
142 	sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].type = SENSOR_TEMP;
143 	sc->sensors[ITHERM_SENSOR_DIMMTEMP1].type = SENSOR_TEMP;
144 	sc->sensors[ITHERM_SENSOR_DIMMTEMP2].type = SENSOR_TEMP;
145 	sc->sensors[ITHERM_SENSOR_DIMMTEMP3].type = SENSOR_TEMP;
146 	sc->sensors[ITHERM_SENSOR_DIMMTEMP4].type = SENSOR_TEMP;
147 	sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].type = SENSOR_TEMP;
148 	sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].type = SENSOR_TEMP;
149 
150 	strlcpy(sc->sensors[ITHERM_SENSOR_THERMOMETER].desc,
151 	    "Thermometer",
152 	    sizeof(sc->sensors[ITHERM_SENSOR_THERMOMETER].desc));
153 
154 	strlcpy(sc->sensors[ITHERM_SENSOR_CORETEMP1].desc,
155 	    "Core 1",
156 	    sizeof(sc->sensors[ITHERM_SENSOR_CORETEMP1].desc));
157 
158 	strlcpy(sc->sensors[ITHERM_SENSOR_CORETEMP2].desc,
159 	    "Core 2",
160 	    sizeof(sc->sensors[ITHERM_SENSOR_CORETEMP2].desc));
161 
162 	strlcpy(sc->sensors[ITHERM_SENSOR_COREENERGY].desc,
163 	    "CPU power consumption",
164 	    sizeof(sc->sensors[ITHERM_SENSOR_COREENERGY].desc));
165 
166 	strlcpy(sc->sensors[ITHERM_SENSOR_GPUTEMP].desc,
167 	    "GPU/Memory Controller Temp",
168 	    sizeof(sc->sensors[ITHERM_SENSOR_GPUTEMP].desc));
169 
170 	strlcpy(sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].desc,
171 	    "CPU/GPU Max temp",
172 	    sizeof(sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].desc));
173 
174 	strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP1].desc,
175 	    "DIMM 1",
176 	    sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP1].desc));
177 
178 	strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP2].desc,
179 	    "DIMM 2",
180 	    sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP2].desc));
181 
182 	strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP3].desc,
183 	    "DIMM 3",
184 	    sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP3].desc));
185 
186 	strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP4].desc,
187 	    "DIMM 4",
188 	    sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP4].desc));
189 
190 	strlcpy(sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].desc,
191 	    "GPU/Memory controller abs.",
192 	    sizeof(sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].desc));
193 
194 	strlcpy(sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].desc,
195 	    "PCH abs.",
196 	    sizeof(sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].desc));
197 
198 	strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname,
199 	    sizeof(sc->sensordev.xname));
200 
201 	itherm_enable(sc);
202 
203 	for (i = 0; i < ITHERM_NUM_SENSORS; i++)
204 		sensor_attach(&sc->sensordev, &sc->sensors[i]);
205 
206 	sensordev_install(&sc->sensordev);
207 	sensor_task_register(sc, itherm_refresh, ITHERM_REFRESH_INTERVAL);
208 
209 	printf("\n");
210 
211 	return;
212 }
213 
214 void
215 itherm_enable(struct itherm_softc *sc)
216 {
217 	sc->energy_prev = 0;
218 
219 	/* Enable thermal sensor */
220 	IWRITE1(sc, ITHERM_TSE, ITHERM_TSE_ENABLE);
221 
222 	/* Enable thermal reporting */
223 	IWRITE2(sc, ITHERM_TRC, (ITHERM_TEMP_READ_ENABLE |
224 	    ITHERM_TDR_ENABLE | ITHERM_SECOND_CORE_ENABLE));
225 }
226 
227 int
228 itherm_activate(struct device *self, int act)
229 {
230 	struct itherm_softc *sc = (struct itherm_softc *)self;
231 
232 	switch (act) {
233 	case DVACT_RESUME:
234 		itherm_enable(sc);
235 		break;
236 	}
237 
238 	return (0);
239 }
240 
241 void
242 itherm_refresh_sensor_data(struct itherm_softc *sc)
243 {
244 	u_int16_t data;
245 	int64_t energy;
246 	u_int32_t i;
247 
248 	/* Thermometer sensor */
249 	sc->sensors[ITHERM_SENSOR_THERMOMETER].value =
250 	    IREAD1(sc, ITHERM_TSTR);
251 
252 	itherm_bias_temperature_sensor(
253 	    &sc->sensors[ITHERM_SENSOR_THERMOMETER]);
254 
255 	/*
256 	 * The Intel 3400 Thermal Sensor has separate sensors for each
257 	 * core, reported as a 16 bit value. Bits 13:6 are the integer
258 	 * part of the temperature in C and bits 5:0 are the fractional
259 	 * part of the temperature, in 1/64 degree C intervals.
260 	 * Bit 15 is used to indicate an invalid temperature
261 	 */
262 
263 	/* Core 1 temperature */
264     	data = IREAD2(sc, ITHERM_CTV1);
265 	if (data & ITHERM_CTV_INVALID)
266 		sc->sensors[ITHERM_SENSOR_CORETEMP1].flags |=
267 		    SENSOR_FINVALID;
268 	else {
269 		sc->sensors[ITHERM_SENSOR_CORETEMP1].flags &=
270 		    ~SENSOR_FINVALID;
271 		sc->sensors[ITHERM_SENSOR_CORETEMP1].value =
272 		    (data & ITHERM_CTV_INT_MASK) >> 6;
273 		sc->sensors[ITHERM_SENSOR_CORETEMP1].value *=
274 		    1000000;
275 		data &= ITHERM_CTV_FRAC_MASK;
276 		data *= 1000000 / 64;
277 		sc->sensors[ITHERM_SENSOR_CORETEMP1].value +=
278 		    data;
279 		itherm_bias_temperature_sensor(
280 		    &sc->sensors[ITHERM_SENSOR_CORETEMP1]);
281 	}
282 
283 	/* Core 2 temperature */
284     	data = IREAD2(sc, ITHERM_CTV2);
285 	if (data & ITHERM_CTV_INVALID)
286 		sc->sensors[ITHERM_SENSOR_CORETEMP2].flags |=
287 		    SENSOR_FINVALID;
288 	else {
289 		sc->sensors[ITHERM_SENSOR_CORETEMP2].flags &=
290 		    ~SENSOR_FINVALID;
291 		sc->sensors[ITHERM_SENSOR_CORETEMP2].value =
292 		    (data & ITHERM_CTV_INT_MASK) >> 6;
293 		sc->sensors[ITHERM_SENSOR_CORETEMP2].value *=
294 		    1000000;
295 		data &= ITHERM_CTV_FRAC_MASK;
296 		data *= 1000000 / 64;
297 		sc->sensors[ITHERM_SENSOR_CORETEMP2].value +=
298 		    data;
299 		itherm_bias_temperature_sensor(
300 		    &sc->sensors[ITHERM_SENSOR_CORETEMP2]);
301 	}
302 
303 	/*
304 	 * The core energy sensor reports the number of Joules
305 	 * of energy consumed by the processor since powerup.
306 	 * This number is scaled by 65535 and is continually
307 	 * increasing, so we save the old value and compute
308 	 * the difference for the Watt sensor value.
309 	 */
310 
311 	i = IREAD4(sc, ITHERM_CEV1);
312 	/* Convert to Joules per interval */
313 	energy = (i / 65535);
314 	energy = energy - sc->energy_prev;
315 	sc->energy_prev = (i / 65535);
316 	/* Convert to Joules per second */
317 	energy = energy / ITHERM_REFRESH_INTERVAL;
318 	/* Convert to micro Joules per second (micro Watts) */
319 	energy = energy * 1000 * 1000;
320 
321 	sc->sensors[ITHERM_SENSOR_COREENERGY].value = energy;
322 
323 	/*
324 	 * XXX - the GPU temp is reported as a 64 bit value with no
325 	 * documented structure. Disabled for now
326 	 */
327 	sc->sensors[ITHERM_SENSOR_GPUTEMP].flags |= SENSOR_FINVALID;
328 #if 0
329 	bus_space_read_multi_4(sc->iot, sc->ioh, ITHERM_MGTV,
330 	    (u_int32_t *)&sc->sensors[ITHERM_SENSOR_GPUTEMP].value, 2);
331 	sc->sensors[ITHERM_SENSOR_GPUTEMP].value *= 1000000;
332 	sc->sensors[ITHERM_SENSOR_GPUTEMP].value += 273150000;
333 #endif
334 
335 	/* Max processor temperature */
336 	sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].value =
337 	    IREAD1(sc, ITHERM_PTV) * 1000000;
338 	itherm_bias_temperature_sensor(
339 	    &sc->sensors[ITHERM_SENSOR_MAXPROCTEMP]);
340 
341 	/* DIMM 1 */
342 	sc->sensors[ITHERM_SENSOR_DIMMTEMP1].value =
343 	    IREAD1(sc, ITHERM_DTV) * 1000000;
344 	itherm_bias_temperature_sensor(
345 	    &sc->sensors[ITHERM_SENSOR_DIMMTEMP1]);
346 
347 	/* DIMM 2 */
348 	sc->sensors[ITHERM_SENSOR_DIMMTEMP2].value =
349 	    IREAD1(sc, ITHERM_DTV+1) * 1000000;
350 	itherm_bias_temperature_sensor(
351 	    &sc->sensors[ITHERM_SENSOR_DIMMTEMP2]);
352 
353 	/* DIMM 3 */
354 	sc->sensors[ITHERM_SENSOR_DIMMTEMP3].value =
355 	    IREAD1(sc, ITHERM_DTV+2) * 1000000;
356 	itherm_bias_temperature_sensor(
357 	    &sc->sensors[ITHERM_SENSOR_DIMMTEMP3]);
358 
359 	/* DIMM 4 */
360 	sc->sensors[ITHERM_SENSOR_DIMMTEMP4].value =
361 	    IREAD1(sc, ITHERM_DTV+3) * 1000000;
362 	itherm_bias_temperature_sensor(
363 	    &sc->sensors[ITHERM_SENSOR_DIMMTEMP4]);
364 
365 	/* GPU Temperature */
366 	sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].value =
367 	    IREAD1(sc, ITHERM_ITV+1) * 1000000;
368 	itherm_bias_temperature_sensor(
369 	    &sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE]);
370 
371 	/* PCH Temperature */
372 	sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].value =
373 	    IREAD1(sc, ITHERM_ITV) * 1000000;
374 	itherm_bias_temperature_sensor(
375 	    &sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE]);
376 }
377 
378 void
379 itherm_bias_temperature_sensor(struct ksensor *sensor)
380 {
381 	if (sensor->value == 0 || sensor->value == 0xff)
382 		sensor->flags |= SENSOR_FINVALID;
383 	else
384 		sensor->flags &= ~SENSOR_FINVALID;
385 
386 	/* Bias anyway from degC to degK, even if invalid */
387 	sensor->value += 273150000;
388 }
389 
390 void
391 itherm_refresh(void *arg)
392 {
393 	struct itherm_softc *sc = (struct itherm_softc *)arg;
394 
395 	itherm_refresh_sensor_data(sc);
396 }
397