Annotation of sys/dev/isa/viasio.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: viasio.c,v 1.10 2007/06/14 19:13:37 grange Exp $ */
2: /*
3: * Copyright (c) 2005 Alexander Yurchenko <grange@openbsd.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17:
18: /*
19: * VIA VT1211 LPC Super I/O driver.
20: */
21:
22: #include <sys/param.h>
23: #include <sys/systm.h>
24: #include <sys/device.h>
25: #include <sys/kernel.h>
26: #include <sys/sensors.h>
27: #include <sys/timeout.h>
28:
29: #include <machine/bus.h>
30:
31: #include <dev/isa/isareg.h>
32: #include <dev/isa/isavar.h>
33:
34: #include <dev/isa/viasioreg.h>
35:
36: #ifdef VIASIO_DEBUG
37: #define DPRINTF(x) printf x
38: #else
39: #define DPRINTF(x)
40: #endif
41:
42: /* autoconf flags */
43: #define VIASIO_CFFLAGS_HM_ENABLE 0x0001 /* enable HM if disabled */
44: #define VIASIO_CFFLAGS_WDG_ENABLE 0x0002 /* enable WDG if disabled */
45:
46: struct viasio_softc {
47: struct device sc_dev;
48:
49: bus_space_tag_t sc_iot;
50: bus_space_handle_t sc_ioh;
51:
52: /* Hardware monitor */
53: bus_space_handle_t sc_hm_ioh;
54: int sc_hm_clock;
55: struct ksensor sc_hm_sensors[VT1211_HM_NSENSORS];
56: struct ksensordev sc_sensordev;
57: struct timeout sc_hm_timo;
58:
59: /* Watchdog timer */
60: bus_space_handle_t sc_wdg_ioh;
61: };
62:
63: int viasio_probe(struct device *, void *, void *);
64: void viasio_attach(struct device *, struct device *, void *);
65:
66: void viasio_hm_init(struct viasio_softc *);
67: void viasio_hm_refresh(void *);
68:
69: void viasio_wdg_init(struct viasio_softc *);
70: int viasio_wdg_cb(void *, int);
71:
72: struct cfattach viasio_ca = {
73: sizeof(struct viasio_softc),
74: viasio_probe,
75: viasio_attach
76: };
77:
78: struct cfdriver viasio_cd = {
79: NULL, "viasio", DV_DULL
80: };
81:
82: static __inline void
83: viasio_conf_enable(bus_space_tag_t iot, bus_space_handle_t ioh)
84: {
85: bus_space_write_1(iot, ioh, VT1211_INDEX, VT1211_CONF_EN_MAGIC);
86: bus_space_write_1(iot, ioh, VT1211_INDEX, VT1211_CONF_EN_MAGIC);
87: }
88:
89: static __inline void
90: viasio_conf_disable(bus_space_tag_t iot, bus_space_handle_t ioh)
91: {
92: bus_space_write_1(iot, ioh, VT1211_INDEX, VT1211_CONF_DS_MAGIC);
93: }
94:
95: static __inline u_int8_t
96: viasio_conf_read(bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t index)
97: {
98: bus_space_write_1(iot, ioh, VT1211_INDEX, index);
99: return (bus_space_read_1(iot, ioh, VT1211_DATA));
100: }
101:
102: static __inline void
103: viasio_conf_write(bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t index,
104: u_int8_t data)
105: {
106: bus_space_write_1(iot, ioh, VT1211_INDEX, index);
107: bus_space_write_1(iot, ioh, VT1211_DATA, data);
108: }
109:
110: static __inline int64_t
111: viasio_raw2temp(int raw)
112: {
113: int tblsize = sizeof(vt1211_hm_temptbl) / sizeof(vt1211_hm_temptbl[0]);
114: int i;
115: int raw1, raw2;
116: int64_t temp = -1, temp1, temp2;
117:
118: if (raw < vt1211_hm_temptbl[0].raw ||
119: raw > vt1211_hm_temptbl[tblsize - 1].raw)
120: return (-1);
121:
122: for (i = 0; i < tblsize - 1; i++) {
123: raw1 = vt1211_hm_temptbl[i].raw;
124: temp1 = vt1211_hm_temptbl[i].temp;
125: raw2 = vt1211_hm_temptbl[i + 1].raw;
126: temp2 = vt1211_hm_temptbl[i + 1].temp;
127:
128: if (raw >= raw1 && raw <= raw2) {
129: /* linear interpolation */
130: temp = temp1 + ((raw - raw1) * (temp2 - temp1)) /
131: (raw2 - raw1);
132: break;
133: }
134: }
135:
136: return (temp);
137: }
138:
139: int
140: viasio_probe(struct device *parent, void *match, void *aux)
141: {
142: struct isa_attach_args *ia = aux;
143: bus_space_tag_t iot;
144: bus_space_handle_t ioh;
145: u_int8_t reg;
146:
147: /* Match by device ID */
148: iot = ia->ia_iot;
149: if (bus_space_map(iot, ia->ipa_io[0].base, VT1211_IOSIZE, 0, &ioh))
150: return (0);
151: viasio_conf_enable(iot, ioh);
152: reg = viasio_conf_read(iot, ioh, VT1211_ID);
153: DPRINTF(("viasio_probe: id 0x%02x\n", reg));
154: viasio_conf_disable(iot, ioh);
155: bus_space_unmap(iot, ioh, VT1211_IOSIZE);
156: if (reg == VT1211_ID_VT1211) {
157: ia->ipa_nio = 1;
158: ia->ipa_io[0].length = VT1211_IOSIZE;
159: ia->ipa_nmem = 0;
160: ia->ipa_nirq = 0;
161: ia->ipa_ndrq = 0;
162: return (1);
163: }
164:
165: return (0);
166: }
167:
168: void
169: viasio_attach(struct device *parent, struct device *self, void *aux)
170: {
171: struct viasio_softc *sc = (void *)self;
172: struct isa_attach_args *ia = aux;
173: u_int8_t reg;
174:
175: /* Map ISA I/O space */
176: sc->sc_iot = ia->ia_iot;
177: if (bus_space_map(sc->sc_iot, ia->ipa_io[0].base,
178: VT1211_IOSIZE, 0, &sc->sc_ioh)) {
179: printf(": can't map I/O space\n");
180: return;
181: }
182:
183: /* Enter configuration mode */
184: viasio_conf_enable(sc->sc_iot, sc->sc_ioh);
185:
186: /* Read device revision */
187: reg = viasio_conf_read(sc->sc_iot, sc->sc_ioh, VT1211_REV);
188: printf(": VT1211 rev 0x%02x", reg);
189:
190: /* Initialize logical devices */
191: viasio_hm_init(sc);
192: viasio_wdg_init(sc);
193: printf("\n");
194:
195: /* Escape from configuration mode */
196: viasio_conf_disable(sc->sc_iot, sc->sc_ioh);
197: }
198:
199: void
200: viasio_hm_init(struct viasio_softc *sc)
201: {
202: u_int8_t reg0, reg1;
203: u_int16_t iobase;
204: int i;
205:
206: printf(", HM");
207:
208: /* Select HM logical device */
209: viasio_conf_write(sc->sc_iot, sc->sc_ioh, VT1211_LDN, VT1211_LDN_HM);
210:
211: /*
212: * Check if logical device is activated by firmware. If not
213: * try to activate it only if requested.
214: */
215: reg0 = viasio_conf_read(sc->sc_iot, sc->sc_ioh, VT1211_HM_ACT);
216: DPRINTF((": ACT 0x%02x", reg0));
217: if ((reg0 & VT1211_HM_ACT_EN) == 0) {
218: if ((sc->sc_dev.dv_cfdata->cf_flags &
219: VIASIO_CFFLAGS_HM_ENABLE) != 0) {
220: reg0 |= VT1211_HM_ACT_EN;
221: viasio_conf_write(sc->sc_iot, sc->sc_ioh,
222: VT1211_HM_ACT, reg0);
223: reg0 = viasio_conf_read(sc->sc_iot, sc->sc_ioh,
224: VT1211_HM_ACT);
225: DPRINTF((", new ACT 0x%02x", reg0));
226: if ((reg0 & VT1211_HM_ACT_EN) == 0) {
227: printf(" failed to activate");
228: return;
229: }
230: } else {
231: printf(" not activated");
232: return;
233: }
234: }
235:
236: /* Read HM I/O space address */
237: reg0 = viasio_conf_read(sc->sc_iot, sc->sc_ioh, VT1211_HM_ADDR_LSB);
238: reg1 = viasio_conf_read(sc->sc_iot, sc->sc_ioh, VT1211_HM_ADDR_MSB);
239: iobase = (reg1 << 8) | reg0;
240: DPRINTF((", addr 0x%04x", iobase));
241:
242: /* Map HM I/O space */
243: if (bus_space_map(sc->sc_iot, iobase, VT1211_HM_IOSIZE, 0,
244: &sc->sc_hm_ioh)) {
245: printf(" can't map I/O space");
246: return;
247: }
248:
249: /*
250: * Check if hardware monitoring is enabled by firmware. If not
251: * try to enable it only if requested.
252: */
253: reg0 = bus_space_read_1(sc->sc_iot, sc->sc_hm_ioh, VT1211_HM_CONF);
254: DPRINTF((", CONF 0x%02x", reg0));
255: if ((reg0 & VT1211_HM_CONF_START) == 0) {
256: if ((sc->sc_dev.dv_cfdata->cf_flags &
257: VIASIO_CFFLAGS_HM_ENABLE) != 0) {
258: reg0 |= VT1211_HM_CONF_START;
259: bus_space_write_1(sc->sc_iot, sc->sc_hm_ioh,
260: VT1211_HM_CONF, reg0);
261: reg0 = bus_space_read_1(sc->sc_iot, sc->sc_hm_ioh,
262: VT1211_HM_CONF);
263: DPRINTF((", new CONF 0x%02x", reg0));
264: if ((reg0 & VT1211_HM_CONF_START) == 0) {
265: printf(" failed to enable monitoring");
266: return;
267: }
268: } else {
269: printf(" monitoring not enabled");
270: return;
271: }
272: }
273:
274: /* Read PWM clock frequency */
275: reg0 = bus_space_read_1(sc->sc_iot, sc->sc_hm_ioh, VT1211_HM_PWMCS);
276: sc->sc_hm_clock = vt1211_hm_clock[reg0 & 0x07];
277: DPRINTF((", PWMCS 0x%02x, %dHz", reg0, sc->sc_hm_clock));
278:
279: /* Temperature reading 1 */
280: sc->sc_hm_sensors[VT1211_HMS_TEMP1].type = SENSOR_TEMP;
281:
282: /* Universal channels (UCH) 1-5 */
283: reg0 = bus_space_read_1(sc->sc_iot, sc->sc_hm_ioh, VT1211_HM_UCHCONF);
284: DPRINTF((", UCHCONF 0x%02x", reg0));
285: for (i = 1; i <= 5; i++) {
286: /* UCH can be configured either as thermal or voltage input */
287: if (VT1211_HM_UCHCONF_ISTEMP(reg0, i)) {
288: sc->sc_hm_sensors[VT1211_HMS_UCH1 + i - 1].type =
289: SENSOR_TEMP;
290: } else {
291: sc->sc_hm_sensors[VT1211_HMS_UCH1 + i - 1].type =
292: SENSOR_VOLTS_DC;
293: }
294: snprintf(sc->sc_hm_sensors[VT1211_HMS_UCH1 + i - 1].desc,
295: sizeof(sc->sc_hm_sensors[VT1211_HMS_UCH1 + i - 1].desc),
296: "UCH%d", i);
297: }
298:
299: /* Internal +3.3V */
300: sc->sc_hm_sensors[VT1211_HMS_33V].type = SENSOR_VOLTS_DC;
301: strlcpy(sc->sc_hm_sensors[VT1211_HMS_33V].desc, "+3.3V",
302: sizeof(sc->sc_hm_sensors[VT1211_HMS_33V].desc));
303:
304: /* FAN reading 1, 2 */
305: sc->sc_hm_sensors[VT1211_HMS_FAN1].type = SENSOR_FANRPM;
306: sc->sc_hm_sensors[VT1211_HMS_FAN2].type = SENSOR_FANRPM;
307:
308: /* Start sensors */
309: strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
310: sizeof(sc->sc_sensordev.xname));
311: for (i = 0; i < VT1211_HM_NSENSORS; i++)
312: sensor_attach(&sc->sc_sensordev, &sc->sc_hm_sensors[i]);
313: sensordev_install(&sc->sc_sensordev);
314: timeout_set(&sc->sc_hm_timo, viasio_hm_refresh, sc);
315: timeout_add(&sc->sc_hm_timo, hz);
316: }
317:
318: void
319: viasio_hm_refresh(void *arg)
320: {
321: struct viasio_softc *sc = arg;
322: u_int8_t reg0, reg1;
323: int64_t val, rfact;
324: int i;
325:
326: /* TEMP1 is a 10-bit thermal input */
327: reg0 = bus_space_read_1(sc->sc_iot, sc->sc_hm_ioh, VT1211_HM_TEMP1);
328: reg1 = bus_space_read_1(sc->sc_iot, sc->sc_hm_ioh, VT1211_HM_TCONF1);
329: reg1 = VT1211_HM_TCONF1_TEMP1(reg1);
330: val = (reg0 << 2) | reg1;
331:
332: /* Convert to uK */
333: /* XXX: conversion function is guessed */
334: val = viasio_raw2temp(val);
335: if (val == -1) {
336: sc->sc_hm_sensors[VT1211_HMS_TEMP1].flags |= SENSOR_FINVALID;
337: } else {
338: sc->sc_hm_sensors[VT1211_HMS_TEMP1].flags &= ~SENSOR_FINVALID;
339: sc->sc_hm_sensors[VT1211_HMS_TEMP1].value = val;
340: }
341:
342: /* Universal channels 1-5 */
343: for (i = 1; i <= 5; i++) {
344: if (sc->sc_hm_sensors[VT1211_HMS_UCH1 + i - 1].type ==
345: SENSOR_TEMP) {
346: /* UCH is a 10-bit thermal input */
347: reg0 = bus_space_read_1(sc->sc_iot, sc->sc_hm_ioh,
348: VT1211_HM_UCH1 + i - 1);
349: if (i == 1) {
350: reg1 = bus_space_read_1(sc->sc_iot,
351: sc->sc_hm_ioh, VT1211_HM_VID4);
352: reg1 = VT1211_HM_VID4_UCH1(reg1);
353: } else {
354: reg1 = bus_space_read_1(sc->sc_iot,
355: sc->sc_hm_ioh, VT1211_HM_ETR);
356: reg1 = VT1211_HM_ETR_UCH(reg1, i);
357: }
358: val = (reg0 << 2) | reg1;
359:
360: /* Convert to uK */
361: /* XXX: conversion function is guessed */
362: val = viasio_raw2temp(val);
363: if (val == -1) {
364: sc->sc_hm_sensors[VT1211_HMS_UCH1 +
365: i - 1].flags |= SENSOR_FINVALID;
366: } else {
367: sc->sc_hm_sensors[VT1211_HMS_UCH1 +
368: i - 1].flags &= ~SENSOR_FINVALID;
369: sc->sc_hm_sensors[VT1211_HMS_UCH1 +
370: i - 1].value = val;
371: }
372: } else {
373: /* UCH is a voltage input */
374: reg0 = bus_space_read_1(sc->sc_iot, sc->sc_hm_ioh,
375: VT1211_HM_UCH1 + i - 1);
376: val = reg0;
377:
378: /* Convert to uV */
379: /* XXX: conversion function is guessed */
380: rfact = vt1211_hm_vrfact[i - 1];
381: sc->sc_hm_sensors[VT1211_HMS_UCH1 + i - 1].value =
382: ((val * 100000000000ULL) / (rfact * 958));
383: }
384: }
385:
386: /* Read internal +3.3V */
387: reg0 = bus_space_read_1(sc->sc_iot, sc->sc_hm_ioh, VT1211_HM_33V);
388: val = reg0;
389:
390: /* Convert to uV */
391: /* XXX: conversion function is guessed */
392: rfact = vt1211_hm_vrfact[5];
393: sc->sc_hm_sensors[VT1211_HMS_33V].value = ((val * 100000000000ULL) /
394: (rfact * 958));
395:
396: /* Read FAN1 clock counter and divisor */
397: reg0 = bus_space_read_1(sc->sc_iot, sc->sc_hm_ioh, VT1211_HM_FAN1);
398: reg1 = bus_space_read_1(sc->sc_iot, sc->sc_hm_ioh, VT1211_HM_FSCTL);
399: reg1 = VT1211_HM_FSCTL_DIV1(reg1);
400: val = reg0 << reg1;
401:
402: /* Convert to RPM */
403: /* XXX: conversion function is guessed */
404: if (val != 0) {
405: sc->sc_hm_sensors[VT1211_HMS_FAN1].value =
406: (sc->sc_hm_clock * 60 / 2) / val;
407: sc->sc_hm_sensors[VT1211_HMS_FAN1].flags &= ~SENSOR_FINVALID;
408: } else {
409: sc->sc_hm_sensors[VT1211_HMS_FAN1].flags |= SENSOR_FINVALID;
410: }
411:
412: /* Read FAN2 clock counter and divisor */
413: reg0 = bus_space_read_1(sc->sc_iot, sc->sc_hm_ioh, VT1211_HM_FAN2);
414: reg1 = bus_space_read_1(sc->sc_iot, sc->sc_hm_ioh, VT1211_HM_FSCTL);
415: reg1 = VT1211_HM_FSCTL_DIV2(reg1);
416: val = reg0 << reg1;
417:
418: /* Convert to RPM */
419: /* XXX: conversion function is guessed */
420: if (val != 0) {
421: sc->sc_hm_sensors[VT1211_HMS_FAN2].value =
422: (sc->sc_hm_clock * 60 / 2) / val;
423: sc->sc_hm_sensors[VT1211_HMS_FAN2].flags &= ~SENSOR_FINVALID;
424: } else {
425: sc->sc_hm_sensors[VT1211_HMS_FAN2].flags |= SENSOR_FINVALID;
426: }
427:
428: timeout_add(&sc->sc_hm_timo, hz);
429: }
430:
431: void
432: viasio_wdg_init(struct viasio_softc *sc)
433: {
434: u_int8_t reg0, reg1;
435: u_int16_t iobase;
436:
437: printf(", WDG");
438:
439: /* Select WDG logical device */
440: viasio_conf_write(sc->sc_iot, sc->sc_ioh, VT1211_LDN, VT1211_LDN_WDG);
441:
442: /*
443: * Check if logical device is activated by firmware. If not
444: * try to activate it only if requested.
445: */
446: reg0 = viasio_conf_read(sc->sc_iot, sc->sc_ioh, VT1211_WDG_ACT);
447: DPRINTF((": ACT 0x%02x", reg0));
448: if ((reg0 & VT1211_WDG_ACT_EN) == 0) {
449: if ((sc->sc_dev.dv_cfdata->cf_flags &
450: VIASIO_CFFLAGS_WDG_ENABLE) != 0) {
451: reg0 |= VT1211_WDG_ACT_EN;
452: viasio_conf_write(sc->sc_iot, sc->sc_ioh,
453: VT1211_WDG_ACT, reg0);
454: reg0 = viasio_conf_read(sc->sc_iot, sc->sc_ioh,
455: VT1211_WDG_ACT);
456: DPRINTF((", new ACT 0x%02x", reg0));
457: if ((reg0 & VT1211_WDG_ACT_EN) == 0) {
458: printf(" failed to activate");
459: return;
460: }
461: } else {
462: printf(" not activated");
463: return;
464: }
465: }
466:
467: /* Read WDG I/O space address */
468: reg0 = viasio_conf_read(sc->sc_iot, sc->sc_ioh, VT1211_WDG_ADDR_LSB);
469: reg1 = viasio_conf_read(sc->sc_iot, sc->sc_ioh, VT1211_WDG_ADDR_MSB);
470: iobase = (reg1 << 8) | reg0;
471: DPRINTF((", addr 0x%04x", iobase));
472:
473: /* Map WDG I/O space */
474: if (bus_space_map(sc->sc_iot, iobase, VT1211_WDG_IOSIZE, 0,
475: &sc->sc_wdg_ioh)) {
476: printf(" can't map I/O space");
477: return;
478: }
479:
480: /* Register new watchdog */
481: wdog_register(sc, viasio_wdg_cb);
482: }
483:
484: int
485: viasio_wdg_cb(void *arg, int period)
486: {
487: struct viasio_softc *sc = arg;
488: int mins;
489:
490: mins = (period + 59) / 60;
491: if (mins > 255)
492: mins = 255;
493:
494: bus_space_write_1(sc->sc_iot, sc->sc_wdg_ioh, VT1211_WDG_TIMEOUT, mins);
495: DPRINTF(("viasio_wdg_cb: %d mins\n", mins));
496:
497: return (mins * 60);
498: }
CVSweb