1 /* $OpenBSD: it.c,v 1.48 2022/04/16 19:32:22 naddy Exp $ */
2
3 /*
4 * Copyright (c) 2007-2008 Oleg Safiullin <form@pdp-11.org.ru>
5 * Copyright (c) 2006-2007 Juan Romero Pardines <juan@xtrarom.org>
6 * Copyright (c) 2003 Julien Bordet <zejames@greyhats.org>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/device.h>
33 #include <sys/sensors.h>
34
35 #include <machine/bus.h>
36
37 #include <dev/isa/isavar.h>
38 #include <dev/isa/itvar.h>
39
40
41 #if defined(ITDEBUG)
42 #define DPRINTF(x) do { printf x; } while (0)
43 #else
44 #define DPRINTF(x)
45 #endif
46
47
48 int it_match(struct device *, void *, void *);
49 void it_attach(struct device *, struct device *, void *);
50 int it_activate(struct device *, int);
51 u_int8_t it_readreg(bus_space_tag_t, bus_space_handle_t, int);
52 void it_writereg(bus_space_tag_t, bus_space_handle_t, int, u_int8_t);
53 void it_enter(bus_space_tag_t, bus_space_handle_t, int);
54 void it_exit(bus_space_tag_t, bus_space_handle_t);
55
56 u_int8_t it_ec_readreg(struct it_softc *, int);
57 void it_ec_writereg(struct it_softc *, int, u_int8_t);
58 void it_ec_refresh(void *arg);
59
60 int it_wdog_cb(void *, int);
61
62 /*
63 * IT87-compatible chips can typically measure voltages up to 4.096 V.
64 * To measure higher voltages the input is attenuated with (external)
65 * resistors. Negative voltages are measured using a reference
66 * voltage. So we have to convert the sensor values back to real
67 * voltages by applying the appropriate resistor factor.
68 */
69 #define RFACT_NONE 10000
70 #define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y))
71
72
73 const struct {
74 enum sensor_type type;
75 const char *desc;
76 } it_sensors[IT_EC_NUMSENSORS] = {
77 #define IT_TEMP_BASE 0
78 #define IT_TEMP_COUNT 3
79 { SENSOR_TEMP, NULL },
80 { SENSOR_TEMP, NULL },
81 { SENSOR_TEMP, NULL },
82
83 #define IT_FAN_BASE 3
84 #define IT_FAN_COUNT 5
85 { SENSOR_FANRPM, NULL },
86 { SENSOR_FANRPM, NULL },
87 { SENSOR_FANRPM, NULL },
88 { SENSOR_FANRPM, NULL },
89 { SENSOR_FANRPM, NULL },
90
91 #define IT_VOLT_BASE 8
92 #define IT_VOLT_COUNT 9
93 { SENSOR_VOLTS_DC, "VCORE_A" },
94 { SENSOR_VOLTS_DC, "VCORE_B" },
95 { SENSOR_VOLTS_DC, "+3.3V" },
96 { SENSOR_VOLTS_DC, "+5V" },
97 { SENSOR_VOLTS_DC, "+12V" },
98 { SENSOR_VOLTS_DC, "-12V" },
99 { SENSOR_VOLTS_DC, "-5V" },
100 { SENSOR_VOLTS_DC, "+5VSB" },
101 { SENSOR_VOLTS_DC, "VBAT" }
102 };
103
104 /* rfact values for voltage sensors */
105 const int it_vrfact[IT_VOLT_COUNT] = {
106 RFACT_NONE, /* VCORE_A */
107 RFACT_NONE, /* VCORE_A */
108 RFACT_NONE, /* +3.3V */
109 RFACT(68, 100), /* +5V */
110 RFACT(30, 10), /* +12V */
111 RFACT(83, 20), /* -12V */
112 RFACT(21, 10), /* -5V */
113 RFACT(68, 100), /* +5VSB */
114 RFACT_NONE /* VBAT */
115 };
116
117 const int it_fan_regs[] = {
118 IT_EC_FAN_TAC1, IT_EC_FAN_TAC2, IT_EC_FAN_TAC3,
119 IT_EC_FAN_TAC4_LSB, IT_EC_FAN_TAC5_LSB
120 };
121
122 const int it_fan_ext_regs[] = {
123 IT_EC_FAN_EXT_TAC1, IT_EC_FAN_EXT_TAC2, IT_EC_FAN_EXT_TAC3,
124 IT_EC_FAN_TAC4_MSB, IT_EC_FAN_TAC5_MSB
125 };
126
127 LIST_HEAD(, it_softc) it_softc_list = LIST_HEAD_INITIALIZER(it_softc_list);
128
129
130 int
it_match(struct device * parent,void * match,void * aux)131 it_match(struct device *parent, void *match, void *aux)
132 {
133 struct isa_attach_args *ia = aux;
134 struct it_softc *sc;
135 bus_space_handle_t ioh;
136 int ec_iobase, found = 0;
137 u_int16_t cr;
138
139 if (ia->ipa_io[0].base != IO_IT1 && ia->ipa_io[0].base != IO_IT2)
140 return (0);
141
142 /* map i/o space */
143 if (bus_space_map(ia->ia_iot, ia->ipa_io[0].base, 2, 0, &ioh) != 0) {
144 DPRINTF(("it_match: can't map i/o space"));
145 return (0);
146 }
147
148 /* enter MB PnP mode */
149 it_enter(ia->ia_iot, ioh, ia->ipa_io[0].base);
150
151 /*
152 * SMSC or similar SuperIO chips use 0x55 magic to enter PnP mode
153 * and 0xaa to exit. These chips also enter PnP mode via ITE
154 * `enter MB PnP mode' sequence, so force chip to exit PnP mode
155 * if this is the case.
156 */
157 bus_space_write_1(ia->ia_iot, ioh, IT_IO_ADDR, 0xaa);
158
159 /* get chip id */
160 cr = it_readreg(ia->ia_iot, ioh, IT_CHIPID1) << 8;
161 cr |= it_readreg(ia->ia_iot, ioh, IT_CHIPID2);
162
163 switch (cr) {
164 case IT_ID_8705:
165 case IT_ID_8712:
166 case IT_ID_8716:
167 case IT_ID_8718:
168 case IT_ID_8720:
169 case IT_ID_8721:
170 case IT_ID_8726:
171 case IT_ID_8728:
172 case IT_ID_8772:
173 /* get environment controller base address */
174 it_writereg(ia->ia_iot, ioh, IT_LDN, IT_EC_LDN);
175 ec_iobase = it_readreg(ia->ia_iot, ioh, IT_EC_MSB) << 8;
176 ec_iobase |= it_readreg(ia->ia_iot, ioh, IT_EC_LSB);
177
178 /* check if device already attached */
179 LIST_FOREACH(sc, &it_softc_list, sc_list)
180 if (sc->sc_ec_iobase == ec_iobase)
181 break;
182
183 if (sc == NULL) {
184 ia->ipa_nio = 1;
185 ia->ipa_io[0].length = 2;
186 ia->ipa_nmem = ia->ipa_nirq = ia->ipa_ndrq = 0;
187 found++;
188 }
189
190 break;
191 }
192
193 /* exit MB PnP mode */
194 it_exit(ia->ia_iot, ioh);
195
196 /* unmap i/o space */
197 bus_space_unmap(ia->ia_iot, ioh, 2);
198
199 return (found);
200 }
201
202 void
it_attach(struct device * parent,struct device * self,void * aux)203 it_attach(struct device *parent, struct device *self, void *aux)
204 {
205 struct it_softc *sc = (void *)self;
206 struct isa_attach_args *ia = aux;
207 int i;
208
209 sc->sc_iot = ia->ia_iot;
210 sc->sc_iobase = ia->ipa_io[0].base;
211 if (bus_space_map(sc->sc_iot, sc->sc_iobase, 2, 0, &sc->sc_ioh) != 0) {
212 printf(": can't map i/o space\n");
213 return;
214 }
215
216 /* enter MB PnP mode */
217 it_enter(sc->sc_iot, sc->sc_ioh, sc->sc_iobase);
218
219 /* get chip id and rev */
220 sc->sc_chipid = it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPID1) << 8;
221 sc->sc_chipid |= it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPID2);
222 sc->sc_chiprev = it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPREV) & 0x0f;
223
224 /* get environment controller base address */
225 it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_EC_LDN);
226 sc->sc_ec_iobase = it_readreg(sc->sc_iot, sc->sc_ioh, IT_EC_MSB) << 8;
227 sc->sc_ec_iobase |= it_readreg(sc->sc_iot, sc->sc_ioh, IT_EC_LSB);
228
229 /* initialize watchdog timer */
230 if (sc->sc_chipid != IT_ID_8705) {
231 it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_WDT_LDN);
232 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_CSR, 0x00);
233 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 0x00);
234 wdog_register(it_wdog_cb, sc);
235 }
236
237 /* exit MB PnP mode and unmap */
238 it_exit(sc->sc_iot, sc->sc_ioh);
239
240 LIST_INSERT_HEAD(&it_softc_list, sc, sc_list);
241 printf(": IT%xF rev %X", sc->sc_chipid, sc->sc_chiprev);
242
243 if (sc->sc_ec_iobase == 0) {
244 printf(", EC disabled\n");
245 return;
246 }
247
248 printf(", EC port 0x%x\n", sc->sc_ec_iobase);
249
250 /* map environment controller i/o space */
251 sc->sc_ec_iot = ia->ia_iot;
252 if (bus_space_map(sc->sc_ec_iot, sc->sc_ec_iobase, 8, 0,
253 &sc->sc_ec_ioh) != 0) {
254 printf("%s: can't map EC i/o space\n", sc->sc_dev.dv_xname);
255 return;
256 }
257
258 /* initialize sensor structures */
259 for (i = 0; i < IT_EC_NUMSENSORS; i++) {
260 sc->sc_sensors[i].type = it_sensors[i].type;
261
262 if (it_sensors[i].desc != NULL)
263 strlcpy(sc->sc_sensors[i].desc, it_sensors[i].desc,
264 sizeof(sc->sc_sensors[i].desc));
265 }
266
267 /* register sensor update task */
268 if (sensor_task_register(sc, it_ec_refresh, IT_EC_INTERVAL) == NULL) {
269 printf("%s: unable to register update task\n",
270 sc->sc_dev.dv_xname);
271 bus_space_unmap(sc->sc_ec_iot, sc->sc_ec_ioh, 8);
272 return;
273 }
274
275 /* use 16-bit FAN tachometer registers for newer chips */
276 if (sc->sc_chipid != IT_ID_8705 && sc->sc_chipid != IT_ID_8712)
277 it_ec_writereg(sc, IT_EC_FAN_ECER,
278 it_ec_readreg(sc, IT_EC_FAN_ECER) | 0x07);
279
280 /* activate monitoring */
281 it_ec_writereg(sc, IT_EC_CFG,
282 it_ec_readreg(sc, IT_EC_CFG) | IT_EC_CFG_START | IT_EC_CFG_INTCLR);
283
284 /* initialize sensors */
285 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
286 sizeof(sc->sc_sensordev.xname));
287 for (i = 0; i < IT_EC_NUMSENSORS; i++)
288 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
289 sensordev_install(&sc->sc_sensordev);
290 }
291
292 int
it_activate(struct device * self,int act)293 it_activate(struct device *self, int act)
294 {
295 switch (act) {
296 case DVACT_POWERDOWN:
297 wdog_shutdown(self);
298 break;
299 }
300
301 return (0);
302 }
303
304 u_int8_t
it_readreg(bus_space_tag_t iot,bus_space_handle_t ioh,int r)305 it_readreg(bus_space_tag_t iot, bus_space_handle_t ioh, int r)
306 {
307 bus_space_write_1(iot, ioh, IT_IO_ADDR, r);
308 return (bus_space_read_1(iot, ioh, IT_IO_DATA));
309 }
310
311 void
it_writereg(bus_space_tag_t iot,bus_space_handle_t ioh,int r,u_int8_t v)312 it_writereg(bus_space_tag_t iot, bus_space_handle_t ioh, int r, u_int8_t v)
313 {
314 bus_space_write_1(iot, ioh, IT_IO_ADDR, r);
315 bus_space_write_1(iot, ioh, IT_IO_DATA, v);
316 }
317
318 void
it_enter(bus_space_tag_t iot,bus_space_handle_t ioh,int iobase)319 it_enter(bus_space_tag_t iot, bus_space_handle_t ioh, int iobase)
320 {
321 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x87);
322 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x01);
323 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x55);
324 if (iobase == IO_IT1)
325 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x55);
326 else
327 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0xaa);
328 }
329
330 void
it_exit(bus_space_tag_t iot,bus_space_handle_t ioh)331 it_exit(bus_space_tag_t iot, bus_space_handle_t ioh)
332 {
333 bus_space_write_1(iot, ioh, IT_IO_ADDR, IT_CCR);
334 bus_space_write_1(iot, ioh, IT_IO_DATA, 0x02);
335 }
336
337 u_int8_t
it_ec_readreg(struct it_softc * sc,int r)338 it_ec_readreg(struct it_softc *sc, int r)
339 {
340 bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_ADDR, r);
341 return (bus_space_read_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_DATA));
342 }
343
344 void
it_ec_writereg(struct it_softc * sc,int r,u_int8_t v)345 it_ec_writereg(struct it_softc *sc, int r, u_int8_t v)
346 {
347 bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_ADDR, r);
348 bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_DATA, v);
349 }
350
351 void
it_ec_refresh(void * arg)352 it_ec_refresh(void *arg)
353 {
354 struct it_softc *sc = arg;
355 int i, sdata, divisor, odivisor, ndivisor;
356 u_int8_t cr, ecr;
357
358 /* refresh temp sensors */
359 cr = it_ec_readreg(sc, IT_EC_ADC_TEMPER);
360
361 for (i = 0; i < IT_TEMP_COUNT; i++) {
362 sc->sc_sensors[IT_TEMP_BASE + i].flags &=
363 SENSOR_FINVALID;
364
365 if (!(cr & (1 << i)) && !(cr & (1 << (i + 3)))) {
366 sc->sc_sensors[IT_TEMP_BASE + i].flags |=
367 SENSOR_FINVALID;
368 continue;
369 }
370
371 sdata = it_ec_readreg(sc, IT_EC_TEMPBASE + i);
372 /* convert to degF */
373 sc->sc_sensors[IT_TEMP_BASE + i].value =
374 sdata * 1000000 + 273150000;
375 }
376
377 /* refresh volt sensors */
378 cr = it_ec_readreg(sc, IT_EC_ADC_VINER);
379
380 for (i = 0; i < IT_VOLT_COUNT; i++) {
381 sc->sc_sensors[IT_VOLT_BASE + i].flags &=
382 SENSOR_FINVALID;
383
384 if ((i < 8) && !(cr & (1 << i))) {
385 sc->sc_sensors[IT_VOLT_BASE + i].flags |=
386 SENSOR_FINVALID;
387 continue;
388 }
389
390 sdata = it_ec_readreg(sc, IT_EC_VOLTBASE + i);
391 /* voltage returned as (mV >> 4) */
392 sc->sc_sensors[IT_VOLT_BASE + i].value = sdata << 4;
393 /* these two values are negative and formula is different */
394 if (i == 5 || i == 6)
395 sc->sc_sensors[IT_VOLT_BASE + i].value -= IT_EC_VREF;
396 /* rfact is (factor * 10^4) */
397 sc->sc_sensors[IT_VOLT_BASE + i].value *= it_vrfact[i];
398 /* division by 10 gets us back to uVDC */
399 sc->sc_sensors[IT_VOLT_BASE + i].value /= 10;
400 if (i == 5 || i == 6)
401 sc->sc_sensors[IT_VOLT_BASE + i].value +=
402 IT_EC_VREF * 1000;
403 }
404
405 /* refresh fan sensors */
406 cr = it_ec_readreg(sc, IT_EC_FAN_MCR);
407
408 if (sc->sc_chipid != IT_ID_8705 && sc->sc_chipid != IT_ID_8712) {
409 /* use 16-bit FAN tachometer registers */
410 ecr = it_ec_readreg(sc, IT_EC_FAN_ECER);
411
412 for (i = 0; i < IT_FAN_COUNT; i++) {
413 sc->sc_sensors[IT_FAN_BASE + i].flags &=
414 ~SENSOR_FINVALID;
415
416 if (i < 3 && !(cr & (1 << (i + 4)))) {
417 sc->sc_sensors[IT_FAN_BASE + i].flags |=
418 SENSOR_FINVALID;
419 continue;
420 } else if (i > 2 && !(ecr & (1 << (i + 1)))) {
421 sc->sc_sensors[IT_FAN_BASE + i].flags |=
422 SENSOR_FINVALID;
423 continue;
424 }
425
426 sdata = it_ec_readreg(sc, it_fan_regs[i]);
427 sdata |= it_ec_readreg(sc, it_fan_ext_regs[i]) << 8;
428
429 if (sdata == 0 || sdata == 0xffff)
430 sc->sc_sensors[IT_FAN_BASE + i].value = 0;
431 else
432 sc->sc_sensors[IT_FAN_BASE + i].value =
433 675000 / sdata;
434 }
435 } else {
436 /* use 8-bit FAN tachometer & FAN divisor registers */
437 odivisor = ndivisor = divisor =
438 it_ec_readreg(sc, IT_EC_FAN_DIV);
439
440 for (i = 0; i < IT_FAN_COUNT; i++) {
441 if (i > 2 || !(cr & (1 << (i + 4)))) {
442 sc->sc_sensors[IT_FAN_BASE + i].flags |=
443 SENSOR_FINVALID;
444 continue;
445 }
446
447 sc->sc_sensors[IT_FAN_BASE + i].flags &=
448 ~SENSOR_FINVALID;
449
450 sdata = it_ec_readreg(sc, it_fan_regs[i]);
451
452 if (sdata == 0xff) {
453 sc->sc_sensors[IT_FAN_BASE + i].value = 0;
454
455 if (i == 2)
456 ndivisor ^= 0x40;
457 else {
458 ndivisor &= ~(7 << (i * 3));
459 ndivisor |= ((divisor + 1) & 7) <<
460 (i * 3);
461 }
462 } else if (sdata != 0) {
463 if (i == 2)
464 divisor = divisor & 1 ? 3 : 1;
465 sc->sc_sensors[IT_FAN_BASE + i].value =
466 1350000 / (sdata << (divisor & 7));
467 } else
468 sc->sc_sensors[IT_FAN_BASE + i].value = 0;
469 }
470
471 if (ndivisor != odivisor)
472 it_ec_writereg(sc, IT_EC_FAN_DIV, ndivisor);
473 }
474 }
475
476 int
it_wdog_cb(void * arg,int period)477 it_wdog_cb(void *arg, int period)
478 {
479 struct it_softc *sc = arg;
480 int minutes = 0;
481
482 /* enter MB PnP mode and select WDT device */
483 it_enter(sc->sc_iot, sc->sc_ioh, sc->sc_iobase);
484 it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_WDT_LDN);
485
486 /* disable watchdog timer */
487 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 0x00);
488
489 /* 1000s should be enough for everyone */
490 if (period > 1000)
491 period = 1000;
492 else if (period < 0)
493 period = 0;
494
495 if (period > 0) {
496 /*
497 * Older IT8712F chips have 8-bit timeout counter.
498 * Use minutes for 16-bit values for these chips.
499 */
500 if (sc->sc_chipid == IT_ID_8712 && sc->sc_chiprev < 0x8 &&
501 period > 0xff) {
502 if (period % 60 >= 30)
503 period += 60;
504 period /= 60;
505 minutes++;
506 }
507
508 /* set watchdog timeout (low byte) */
509 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TMO_LSB,
510 period & 0xff);
511
512 if (minutes) {
513 /* enable watchdog timer */
514 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR,
515 IT_WDT_TCR_KRST | IT_WDT_TCR_PWROK);
516
517 period *= 60;
518 } else {
519 /* set watchdog timeout (high byte) */
520 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TMO_MSB,
521 period >> 8);
522
523 /* enable watchdog timer */
524 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR,
525 IT_WDT_TCR_SECS | IT_WDT_TCR_KRST |
526 IT_WDT_TCR_PWROK);
527 }
528 }
529
530 /* exit MB PnP mode */
531 it_exit(sc->sc_iot, sc->sc_ioh);
532
533 return (period);
534 }
535
536
537 const struct cfattach it_ca = {
538 sizeof(struct it_softc),
539 it_match,
540 it_attach,
541 NULL,
542 it_activate
543 };
544
545 struct cfdriver it_cd = {
546 NULL, "it", DV_DULL
547 };
548