1/* $NetBSD: ug.c,v 1.11 2008/03/26 16:09:37 xtraeme Exp $ */
2
3/*
4 * Copyright (c) 2007 Mihai Chelaru <kefren@netbsd.ro>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__KERNEL_RCSID(0, "$NetBSD: ug.c,v 1.11 2008/03/26 16:09:37 xtraeme Exp $");
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/kernel.h>
34#include <sys/proc.h>
35#include <sys/device.h>
36#include <sys/malloc.h>
37#include <sys/errno.h>
38#include <sys/conf.h>
39#include <sys/envsys.h>
40#include <sys/time.h>
41
42#include <sys/bus.h>
43#include <sys/intr.h>
44
45#include <dev/isa/isareg.h>
46#include <dev/isa/isavar.h>
47
48#include <dev/sysmon/sysmonvar.h>
49
50#include <dev/ic/ugreg.h>
51#include <dev/ic/ugvar.h>
52
53uint8_t ug_ver;
54
55/*
56 * Imported from linux driver
57 */
58
59struct ug2_motherboard_info ug2_mb[] = {
60	{ 0x000C, "unknown. Please send-pr(1)", {
61		{ "CPU Core", 0, 0, 10, 1, 0 },
62		{ "DDR", 1, 0, 10, 1, 0 },
63		{ "DDR VTT", 2, 0, 10, 1, 0 },
64		{ "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
65		{ "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
66		{ "MCH 2.5V", 5, 0, 20, 1, 0 },
67		{ "ICH 1.05V", 6, 0, 10, 1, 0 },
68		{ "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
69		{ "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
70		{ "ATX +5V", 9, 0, 30, 1, 0 },
71		{ "+3.3V", 10, 0, 20, 1, 0 },
72		{ "5VSB", 11, 0, 30, 1, 0 },
73		{ "CPU", 24, 1, 1, 1, 0 },
74		{ "System", 25, 1, 1, 1, 0 },
75		{ "PWM", 26, 1, 1, 1, 0 },
76		{ "CPU Fan", 32, 2, 60, 1, 0 },
77		{ "NB Fan", 33, 2, 60, 1, 0 },
78		{ "SYS FAN", 34, 2, 60, 1, 0 },
79		{ "AUX1 Fan", 35, 2, 60, 1, 0 },
80		{ NULL, 0, 0, 0, 0, 0 } }
81	},
82	{ 0x000D, "Abit AW8", {
83		{ "CPU Core", 0, 0, 10, 1, 0 },
84		{ "DDR", 1, 0, 10, 1, 0 },
85		{ "DDR VTT", 2, 0, 10, 1, 0 },
86		{ "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
87		{ "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
88		{ "MCH 2.5V", 5, 0, 20, 1, 0 },
89		{ "ICH 1.05V", 6, 0, 10, 1, 0 },
90		{ "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
91		{ "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
92		{ "ATX +5V", 9, 0, 30, 1, 0 },
93		{ "+3.3V", 10, 0, 20, 1, 0 },
94		{ "5VSB", 11, 0, 30, 1, 0 },
95		{ "CPU", 24, 1, 1, 1, 0 },
96		{ "System", 25, 1, 1, 1, 0 },
97		{ "PWM1", 26, 1, 1, 1, 0 },
98		{ "PWM2", 27, 1, 1, 1, 0 },
99		{ "PWM3", 28, 1, 1, 1, 0 },
100		{ "PWM4", 29, 1, 1, 1, 0 },
101		{ "CPU Fan", 32, 2, 60, 1, 0 },
102		{ "NB Fan", 33, 2, 60, 1, 0 },
103		{ "SYS Fan", 34, 2, 60, 1, 0 },
104		{ "AUX1 Fan", 35, 2, 60, 1, 0 },
105		{ "AUX2 Fan", 36, 2, 60, 1, 0 },
106		{ "AUX3 Fan", 37, 2, 60, 1, 0 },
107		{ "AUX4 Fan", 38, 2, 60, 1, 0 },
108		{ "AUX5 Fan", 39, 2, 60, 1, 0 },
109		{ NULL, 0, 0, 0, 0, 0 } }
110	},
111	{ 0x000E, "Abit AL8", {
112		{ "CPU Core", 0, 0, 10, 1, 0 },
113		{ "DDR", 1, 0, 10, 1, 0 },
114		{ "DDR VTT", 2, 0, 10, 1, 0 },
115		{ "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
116		{ "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
117		{ "MCH 2.5V", 5, 0, 20, 1, 0 },
118		{ "ICH 1.05V", 6, 0, 10, 1, 0 },
119		{ "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
120		{ "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
121		{ "ATX +5V", 9, 0, 30, 1, 0 },
122		{ "+3.3V", 10, 0, 20, 1, 0 },
123		{ "5VSB", 11, 0, 30, 1, 0 },
124		{ "CPU", 24, 1, 1, 1, 0 },
125		{ "System", 25, 1, 1, 1, 0 },
126		{ "PWM", 26, 1, 1, 1, 0 },
127		{ "CPU Fan", 32, 2, 60, 1, 0 },
128		{ "NB Fan", 33, 2, 60, 1, 0 },
129		{ "SYS Fan", 34, 2, 60, 1, 0 },
130		{ NULL, 0, 0, 0, 0, 0 } }
131	},
132	{ 0x000F, "unknown. Please send-pr(1)", {
133		{ "CPU Core", 0, 0, 10, 1, 0 },
134		{ "DDR", 1, 0, 10, 1, 0 },
135		{ "DDR VTT", 2, 0, 10, 1, 0 },
136		{ "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
137		{ "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
138		{ "MCH 2.5V", 5, 0, 20, 1, 0 },
139		{ "ICH 1.05V", 6, 0, 10, 1, 0 },
140		{ "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
141		{ "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
142		{ "ATX +5V", 9, 0, 30, 1, 0 },
143		{ "+3.3V", 10, 0, 20, 1, 0 },
144		{ "5VSB", 11, 0, 30, 1, 0 },
145		{ "CPU", 24, 1, 1, 1, 0 },
146		{ "System", 25, 1, 1, 1, 0 },
147		{ "PWM", 26, 1, 1, 1, 0 },
148		{ "CPU Fan", 32, 2, 60, 1, 0 },
149		{ "NB Fan", 33, 2, 60, 1, 0 },
150		{ "SYS Fan", 34, 2, 60, 1, 0 },
151		{ NULL, 0, 0, 0, 0, 0 } }
152	},
153	{ 0x0010, "Abit NI8 SLI GR", {
154		{ "CPU Core", 0, 0, 10, 1, 0 },
155		{ "DDR", 1, 0, 10, 1, 0 },
156		{ "DDR VTT", 2, 0, 10, 1, 0 },
157		{ "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
158		{ "NB 1.4V", 4, 0, 10, 1, 0 },
159		{ "SB 1.5V", 6, 0, 10, 1, 0 },
160		{ "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
161		{ "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
162		{ "ATX +5V", 9, 0, 30, 1, 0 },
163		{ "+3.3V", 10, 0, 20, 1, 0 },
164		{ "5VSB", 11, 0, 30, 1, 0 },
165		{ "CPU", 24, 1, 1, 1, 0 },
166		{ "SYS", 25, 1, 1, 1, 0 },
167		{ "PWM", 26, 1, 1, 1, 0 },
168		{ "CPU Fan", 32, 2, 60, 1, 0 },
169		{ "NB Fan", 33, 2, 60, 1, 0 },
170		{ "SYS Fan", 34, 2, 60, 1, 0 },
171		{ "AUX1 Fan", 35, 2, 60, 1, 0 },
172		{ "OTES1 Fan", 36, 2, 60, 1, 0 },
173		{ NULL, 0, 0, 0, 0, 0 } }
174	},
175	{ 0x0011, "Abit AT8 32X", {
176		{ "CPU Core", 0, 0, 10, 1, 0 },
177		{ "DDR", 1, 0, 20, 1, 0 },
178		{ "DDR VTT", 2, 0, 10, 1, 0 },
179		{ "CPU VDDA 2.5V", 6, 0, 20, 1, 0 },
180		{ "NB 1.8V", 4, 0, 10, 1, 0 },
181		{ "NB 1.8V Dual", 5, 0, 10, 1, 0 },
182		{ "HTV 1.2", 3, 0, 10, 1, 0 },
183		{ "PCIE 1.2V", 12, 0, 10, 1, 0 },
184		{ "NB 1.2V", 13, 0, 10, 1, 0 },
185		{ "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
186		{ "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
187		{ "ATX +5V", 9, 0, 30, 1, 0 },
188		{ "+3.3V", 10, 0, 20, 1, 0 },
189		{ "5VSB", 11, 0, 30, 1, 0 },
190		{ "CPU", 24, 1, 1, 1, 0 },
191		{ "NB", 25, 1, 1, 1, 0 },
192		{ "System", 26, 1, 1, 1, 0 },
193		{ "PWM", 27, 1, 1, 1, 0 },
194		{ "CPU Fan", 32, 2, 60, 1, 0 },
195		{ "NB Fan", 33, 2, 60, 1, 0 },
196		{ "SYS Fan", 34, 2, 60, 1, 0 },
197		{ "AUX1 Fan", 35, 2, 60, 1, 0 },
198		{ "AUX2 Fan", 36, 2, 60, 1, 0 },
199		{ NULL, 0, 0, 0, 0, 0 } }
200	},
201	{ 0x0012, "unknown. Please send-pr(1)", {
202		{ "CPU Core", 0, 0, 10, 1, 0 },
203		{ "DDR", 1, 0, 20, 1, 0 },
204		{ "DDR VTT", 2, 0, 10, 1, 0 },
205		{ "HyperTransport", 3, 0, 10, 1, 0 },
206		{ "CPU VDDA 2.5V", 5, 0, 20, 1, 0 },
207		{ "NB", 4, 0, 10, 1, 0 },
208		{ "SB", 6, 0, 10, 1, 0 },
209		{ "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
210		{ "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
211		{ "ATX +5V", 9, 0, 30, 1, 0 },
212		{ "+3.3V", 10, 0, 20, 1, 0 },
213		{ "5VSB", 11, 0, 30, 1, 0 },
214		{ "CPU", 24, 1, 1, 1, 0 },
215		{ "SYS", 25, 1, 1, 1, 0 },
216		{ "PWM", 26, 1, 1, 1, 0 },
217		{ "CPU Fan", 32, 2, 60, 1, 0 },
218		{ "NB Fan", 33, 2, 60, 1, 0 },
219		{ "SYS Fan", 34, 2, 60, 1, 0 },
220		{ "AUX1 Fan", 36, 2, 60, 1, 0 },
221		{ NULL, 0, 0, 0, 0, 0 } }
222	},
223	{ 0x0013, "unknown. Please send-pr(1)", {
224		{ "CPU Core", 0, 0, 10, 1, 0 },
225		{ "DDR", 1, 0, 10, 1, 0 },
226		{ "DDR VTT", 2, 0, 10, 1, 0 },
227		{ "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
228		{ "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
229		{ "MCH 2.5V", 5, 0, 20, 1, 0 },
230		{ "ICH 1.05V", 6, 0, 10, 1, 0 },
231		{ "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
232		{ "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
233		{ "ATX +5V", 9, 0, 30, 1, 0 },
234		{ "+3.3V", 10, 0, 20, 1, 0 },
235		{ "5VSB", 11, 0, 30, 1, 0 },
236		{ "CPU", 24, 1, 1, 1, 0 },
237		{ "System", 25, 1, 1, 1, 0 },
238		{ "PWM1", 26, 1, 1, 1, 0 },
239		{ "PWM2", 27, 1, 1, 1, 0 },
240		{ "PWM3", 28, 1, 1, 1, 0 },
241		{ "PWM4", 29, 1, 1, 1, 0 },
242		{ "CPU Fan", 32, 2, 60, 1, 0 },
243		{ "NB Fan", 33, 2, 60, 1, 0 },
244		{ "SYS Fan", 34, 2, 60, 1, 0 },
245		{ "AUX1 Fan", 35, 2, 60, 1, 0 },
246		{ "AUX2 Fan", 36, 2, 60, 1, 0 },
247		{ "AUX3 Fan", 37, 2, 60, 1, 0 },
248		{ "AUX4 Fan", 38, 2, 60, 1, 0 },
249		{ NULL, 0, 0, 0, 0, 0 } }
250	},
251	{ 0x0014, "Abit AB9 Pro", {
252		{ "CPU Core", 0, 0, 10, 1, 0 },
253		{ "DDR", 1, 0, 10, 1, 0 },
254		{ "DDR VTT", 2, 0, 10, 1, 0 },
255		{ "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
256		{ "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
257		{ "MCH 2.5V", 5, 0, 20, 1, 0 },
258		{ "ICH 1.05V", 6, 0, 10, 1, 0 },
259		{ "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
260		{ "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
261		{ "ATX +5V", 9, 0, 30, 1, 0 },
262		{ "+3.3V", 10, 0, 20, 1, 0 },
263		{ "5VSB", 11, 0, 30, 1, 0 },
264		{ "CPU", 24, 1, 1, 1, 0 },
265		{ "System", 25, 1, 1, 1, 0 },
266		{ "PWM", 26, 1, 1, 1, 0 },
267		{ "CPU Fan", 32, 2, 60, 1, 0 },
268		{ "NB Fan", 33, 2, 60, 1, 0 },
269		{ "SYS Fan", 34, 2, 60, 1, 0 },
270		{ NULL, 0, 0, 0, 0, 0 } }
271	},
272	{ 0x0015, "unknown. Please send-pr(1)", {
273		{ "CPU Core", 0, 0, 10, 1, 0 },
274		{ "DDR", 1, 0, 20, 1, 0 },
275		{ "DDR VTT", 2, 0, 10, 1, 0 },
276		{ "HyperTransport", 3, 0, 10, 1, 0 },
277		{ "CPU VDDA 2.5V", 5, 0, 20, 1, 0 },
278		{ "NB", 4, 0, 10, 1, 0 },
279		{ "SB", 6, 0, 10, 1, 0 },
280		{ "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
281		{ "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
282		{ "ATX +5V", 9, 0, 30, 1, 0 },
283		{ "+3.3V", 10, 0, 20, 1, 0 },
284		{ "5VSB", 11, 0, 30, 1, 0 },
285		{ "CPU", 24, 1, 1, 1, 0 },
286		{ "SYS", 25, 1, 1, 1, 0 },
287		{ "PWM", 26, 1, 1, 1, 0 },
288		{ "CPU Fan", 32, 2, 60, 1, 0 },
289		{ "NB Fan", 33, 2, 60, 1, 0 },
290		{ "SYS Fan", 34, 2, 60, 1, 0 },
291		{ "AUX1 Fan", 33, 2, 60, 1, 0 },
292		{ "AUX2 Fan", 35, 2, 60, 1, 0 },
293		{ "AUX3 Fan", 36, 2, 60, 1, 0 },
294		{ NULL, 0, 0, 0, 0, 0 } }
295	},
296	{ 0x0016, "generic", {
297		{ "CPU Core", 0, 0, 10, 1, 0 },
298		{ "DDR", 1, 0, 20, 1, 0 },
299		{ "DDR VTT", 2, 0, 10, 1, 0 },
300		{ "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
301		{ "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
302		{ "MCH 2.5V", 5, 0, 20, 1, 0 },
303		{ "ICH 1.05V", 6, 0, 10, 1, 0 },
304		{ "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
305		{ "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
306		{ "ATX +5V", 9, 0, 30, 1, 0 },
307		{ "+3.3V", 10, 0, 20, 1, 0 },
308		{ "5VSB", 11, 0, 30, 1, 0 },
309		{ "CPU", 24, 1, 1, 1, 0 },
310		{ "System", 25, 1, 1, 1, 0 },
311		{ "PWM", 26, 1, 1, 1, 0 },
312		{ "CPU Fan", 32, 2, 60, 1, 0 },
313		{ "NB Fan", 33, 2, 60, 1, 0 },
314		{ "SYS FAN", 34, 2, 60, 1, 0 },
315		{ "AUX1 Fan", 35, 2, 60, 1, 0 },
316		{ NULL, 0, 0, 0, 0, 0 } }
317	},
318	{ 0x0000, NULL, { { NULL, 0, 0, 0, 0, 0 } } }
319};
320
321
322int
323ug_reset(struct ug_softc *sc)
324{
325	int cnt = 0;
326
327	while (bus_space_read_1(sc->sc_iot, sc->sc_ioh, UG_DATA) != 0x08) {
328	/* 8 meaning Voodoo */
329
330		if (cnt++ > UG_DELAY_CYCLES)
331			return 0;
332
333		bus_space_write_1(sc->sc_iot, sc->sc_ioh, UG_DATA, 0);
334
335		/* Wait for 0x09 at Data Port */
336		if (!ug_waitfor(sc, UG_DATA, 0x09))
337			return 0;
338
339		/* Wait for 0xAC at Cmd Port */
340		if (!ug_waitfor(sc, UG_CMD, 0xAC))
341			return 0;
342	}
343
344	return 1;
345}
346
347uint8_t
348ug_read(struct ug_softc *sc, unsigned short sensor)
349{
350	uint8_t bank, sens, rv;
351
352	bank = (sensor & 0xFF00) >> 8;
353	sens = sensor & 0x00FF;
354
355	bus_space_write_1(sc->sc_iot, sc->sc_ioh, UG_DATA, bank);
356
357	/* Wait 8 at Data Port */
358	if (!ug_waitfor(sc, UG_DATA, 8))
359		return 0;
360
361	bus_space_write_1(sc->sc_iot, sc->sc_ioh, UG_CMD, sens);
362
363	/* Wait 1 at Data Port */
364	if (!ug_waitfor(sc, UG_DATA, 1))
365		return 0;
366
367	/* Finally read the sensor */
368	rv = bus_space_read_1(sc->sc_iot, sc->sc_ioh, UG_CMD);
369
370	ug_reset(sc);
371
372	return rv;
373}
374
375int
376ug_waitfor(struct ug_softc *sc, uint16_t offset, uint8_t value)
377{
378	int cnt = 0;
379	while (bus_space_read_1(sc->sc_iot, sc->sc_ioh, offset) != value) {
380		if (cnt++ > UG_DELAY_CYCLES)
381			return 0;
382	}
383	return 1;
384}
385
386void
387ug_setup_sensors(struct ug_softc *sc)
388{
389	int i;
390
391	/* Setup Temps */
392	for (i = 0; i < UG_VOLT_MIN; i++)
393		sc->sc_sensor[i].units = ENVSYS_STEMP;
394
395#define COPYDESCR(x, y)				\
396	do {					\
397		strlcpy((x), (y), sizeof(x));	\
398	} while (0)
399
400	COPYDESCR(sc->sc_sensor[0].desc, "CPU Temp");
401	COPYDESCR(sc->sc_sensor[1].desc, "SYS Temp");
402	COPYDESCR(sc->sc_sensor[2].desc, "PWN Temp");
403
404	/* Right, Now setup U sensors */
405
406	for (i = UG_VOLT_MIN; i < UG_FAN_MIN; i++) {
407		sc->sc_sensor[i].units = ENVSYS_SVOLTS_DC;
408		sc->sc_sensor[i].rfact = UG_RFACT;
409	}
410
411	COPYDESCR(sc->sc_sensor[3].desc, "HTVdd");
412	COPYDESCR(sc->sc_sensor[4].desc, "VCore");
413	COPYDESCR(sc->sc_sensor[5].desc, "DDRVdd");
414	COPYDESCR(sc->sc_sensor[6].desc, "Vdd3V3");
415	COPYDESCR(sc->sc_sensor[7].desc, "Vdd5V");
416	COPYDESCR(sc->sc_sensor[8].desc, "NBVdd");
417	COPYDESCR(sc->sc_sensor[9].desc, "AGPVdd");
418	COPYDESCR(sc->sc_sensor[10].desc, "DDRVtt");
419	COPYDESCR(sc->sc_sensor[11].desc, "Vdd5VSB");
420	COPYDESCR(sc->sc_sensor[12].desc, "Vdd3VDual");
421	COPYDESCR(sc->sc_sensor[13].desc, "SBVdd");
422
423	/* Fan sensors */
424	for (i = UG_FAN_MIN; i < UG_NUM_SENSORS; i++)
425		sc->sc_sensor[i].units = ENVSYS_SFANRPM;
426
427	COPYDESCR(sc->sc_sensor[14].desc, "CPU Fan");
428	COPYDESCR(sc->sc_sensor[15].desc, "NB Fan");
429	COPYDESCR(sc->sc_sensor[16].desc, "SYS Fan");
430	COPYDESCR(sc->sc_sensor[17].desc, "AUX Fan 1");
431	COPYDESCR(sc->sc_sensor[18].desc, "AUX Fan 2");
432
433	/* All sensors */
434	for (i = 0; i < UG_NUM_SENSORS; i++)
435		sc->sc_sensor[i].units = ENVSYS_SINVALID;
436}
437
438void
439ug_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
440{
441	struct ug_softc *sc = sme->sme_cookie;
442
443	/* Sensors return C while we need uK */
444
445	if (edata->sensor < UG_VOLT_MIN - 1) /* CPU and SYS Temps */
446		edata->value_cur = ug_read(sc, UG_CPUTEMP + edata->sensor)
447		    * 1000000 + 273150000;
448	else if (edata->sensor == 2) /* PWMTEMP */
449		edata->value_cur = ug_read(sc, UG_PWMTEMP)
450		    * 1000000 + 273150000;
451
452	/* Voltages */
453
454#define VOLT_SENSOR	UG_HTV + edata->sensor - UG_VOLT_MIN
455
456	else
457	    if ((edata->sensor >= UG_VOLT_MIN) && (edata->sensor < UG_FAN_MIN)) {
458		edata->value_cur = ug_read(sc, VOLT_SENSOR);
459		switch(VOLT_SENSOR) {
460			case UG_5V:		/* 6V RFact */
461			case UG_5VSB:
462				edata->value_cur *= UG_RFACT6;
463				break;
464			case UG_3V3:		/* 4V RFact */
465			case UG_3VDUAL:
466				edata->value_cur *= UG_RFACT4;
467				break;
468			default:		/* 3V RFact */
469				edata->value_cur *= UG_RFACT3;
470				break;
471		}
472	    } else
473
474#undef VOLT_SENSOR
475
476	/* and Fans */
477	if (edata->sensor >= UG_FAN_MIN)
478		edata->value_cur = ug_read(sc, UG_CPUFAN +
479		    edata->sensor - UG_FAN_MIN) * UG_RFACT_FAN;
480}
481
482void
483ug2_attach(device_t dv)
484{
485	struct ug_softc *sc = device_private(dv);
486	uint8_t buf[2];
487	int i;
488	struct ug2_motherboard_info *ai;
489	struct ug2_sensor_info *si;
490
491	aprint_normal(": Abit uGuru 2005 system monitor\n");
492
493	if (ug2_read(sc, UG2_MISC_BANK, UG2_BOARD_ID, 2, buf) != 2) {
494		aprint_error_dev(dv, "Cannot detect board ID. Using default\n");
495		buf[0] = UG_MAX_MSB_BOARD;
496		buf[1] = UG_MAX_LSB_BOARD;
497	}
498
499	if (buf[0] > UG_MAX_MSB_BOARD || buf[1] > UG_MAX_LSB_BOARD ||
500		buf[1] < UG_MIN_LSB_BOARD) {
501		aprint_error_dev(dv, "Invalid board ID(%X,%X). Using default\n",
502			buf[0], buf[1]);
503		buf[0] = UG_MAX_MSB_BOARD;
504		buf[1] = UG_MAX_LSB_BOARD;
505	}
506
507	ai = &ug2_mb[buf[1] - UG_MIN_LSB_BOARD];
508
509	aprint_normal_dev(dv, "mainboard %s (%.2X%.2X)\n",
510	    ai->name, buf[0], buf[1]);
511
512	sc->mbsens = (void*)ai->sensors;
513	sc->sc_sme = sysmon_envsys_create();
514
515	for (i = 0, si = ai->sensors; si && si->name; si++, i++) {
516		COPYDESCR(sc->sc_sensor[i].desc, si->name);
517		sc->sc_sensor[i].rfact = 1;
518		sc->sc_sensor[i].state = ENVSYS_SVALID;
519		switch (si->type) {
520			case UG2_VOLTAGE_SENSOR:
521				sc->sc_sensor[i].units = ENVSYS_SVOLTS_DC;
522				sc->sc_sensor[i].rfact = UG_RFACT;
523				break;
524			case UG2_TEMP_SENSOR:
525				sc->sc_sensor[i].units = ENVSYS_STEMP;
526				break;
527			case UG2_FAN_SENSOR:
528				sc->sc_sensor[i].units = ENVSYS_SFANRPM;
529				break;
530			default:
531				break;
532		}
533		if (sysmon_envsys_sensor_attach(sc->sc_sme,
534						&sc->sc_sensor[i])) {
535			sysmon_envsys_destroy(sc->sc_sme);
536			return;
537		}
538	}
539#undef COPYDESCR
540
541	sc->sc_sme->sme_name = device_xname(dv);
542	sc->sc_sme->sme_cookie = sc;
543	sc->sc_sme->sme_refresh = ug2_refresh;
544
545	if (sysmon_envsys_register(sc->sc_sme)) {
546		aprint_error_dev(dv, "unable to register with sysmon\n");
547		sysmon_envsys_destroy(sc->sc_sme);
548	}
549}
550
551void
552ug2_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
553{
554	struct ug_softc *sc = sme->sme_cookie;
555	struct ug2_sensor_info *si = (struct ug2_sensor_info *)sc->mbsens;
556	int rfact = 1;
557	uint8_t v;
558
559	si += edata->sensor;
560
561#define SENSOR_VALUE (v * si->multiplier * rfact / si->divisor + si->offset)
562
563	if (ug2_read(sc, UG2_SENSORS_BANK, UG2_VALUES_OFFSET +
564	    si->port, 1, &v) == 1) {
565		switch (si->type) {
566		case UG2_TEMP_SENSOR:
567		    edata->value_cur = SENSOR_VALUE * 1000000
568			+ 273150000;
569		    break;
570		case UG2_VOLTAGE_SENSOR:
571		    rfact = UG_RFACT;
572		    edata->value_cur = SENSOR_VALUE;
573		    break;
574		default:
575		    edata->value_cur = SENSOR_VALUE;
576		    break;
577		}
578	}
579#undef SENSOR_VALUE
580}
581
582int
583ug2_wait_ready(struct ug_softc *sc)
584{
585	int cnt = 0;
586
587	bus_space_write_1(sc->sc_iot, sc->sc_ioh, UG_DATA, 0x1a);
588	while (bus_space_read_1(sc->sc_iot, sc->sc_ioh, UG_DATA) &
589	    UG2_STATUS_BUSY) {
590		if (cnt++ > UG_DELAY_CYCLES)
591			return 0;
592	}
593	return 1;
594}
595
596int
597ug2_wait_readable(struct ug_softc *sc)
598{
599	int cnt = 0;
600
601	while (!(bus_space_read_1(sc->sc_iot, sc->sc_ioh, UG_DATA) &
602		UG2_STATUS_READY_FOR_READ)) {
603		if (cnt++ > UG_DELAY_CYCLES)
604			return 0;
605	}
606	return 1;
607}
608
609int
610ug2_sync(struct ug_softc *sc)
611{
612	int cnt = 0;
613
614#define UG2_WAIT_READY if(ug2_wait_ready(sc) == 0) return 0;
615
616	/* Don't sync two times in a row */
617	if(ug_ver != 0) {
618		ug_ver = 0;
619		return 1;
620	}
621
622	UG2_WAIT_READY;
623	bus_space_write_1(sc->sc_iot, sc->sc_ioh, UG_DATA, 0x20);
624	UG2_WAIT_READY;
625	bus_space_write_1(sc->sc_iot, sc->sc_ioh, UG_CMD, 0x10);
626	UG2_WAIT_READY;
627	bus_space_write_1(sc->sc_iot, sc->sc_ioh, UG_CMD, 0x00);
628	UG2_WAIT_READY;
629	if (ug2_wait_readable(sc) == 0)
630		return 0;
631	while (bus_space_read_1(sc->sc_iot, sc->sc_ioh, UG_CMD) != 0xAC)
632		if (cnt++ > UG_DELAY_CYCLES)
633			return 0;
634	return 1;
635}
636
637int
638ug2_read(struct ug_softc *sc, uint8_t bank, uint8_t offset, uint8_t count,
639	 uint8_t *ret)
640{
641	int i;
642
643	if (ug2_sync(sc) == 0)
644		return 0;
645
646	bus_space_write_1(sc->sc_iot, sc->sc_ioh, UG_DATA, 0x1A);
647	UG2_WAIT_READY;
648	bus_space_write_1(sc->sc_iot, sc->sc_ioh, UG_CMD, bank);
649	UG2_WAIT_READY;
650	bus_space_write_1(sc->sc_iot, sc->sc_ioh, UG_CMD, offset);
651	UG2_WAIT_READY;
652	bus_space_write_1(sc->sc_iot, sc->sc_ioh, UG_CMD, count);
653	UG2_WAIT_READY;
654
655#undef UG2_WAIT_READY
656
657	/* Now wait for the results */
658	for (i = 0; i < count; i++) {
659		if (ug2_wait_readable(sc) == 0)
660			break;
661		ret[i] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, UG_CMD);
662	}
663
664	return i;
665}
666