xref: /openbsd-src/sys/dev/pci/amdpm.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: amdpm.c,v 1.23 2008/06/26 05:42:17 ray Exp $	*/
2 
3 /*
4  * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*-
20  * Copyright (c) 2002 The NetBSD Foundation, Inc.
21  * All rights reserved.
22  *
23  * This code is derived from software contributed to The NetBSD Foundation
24  * by Enami Tsugutomo.
25  *
26  * Redistribution and use in source and binary forms, with or without
27  * modification, are permitted provided that the following conditions
28  * are met:
29  * 1. Redistributions of source code must retain the above copyright
30  *    notice, this list of conditions and the following disclaimer.
31  * 2. Redistributions in binary form must reproduce the above copyright
32  *    notice, this list of conditions and the following disclaimer in the
33  *    documentation and/or other materials provided with the distribution.
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
36  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
37  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
39  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
42  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
43  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
44  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
45  * POSSIBILITY OF SUCH DAMAGE.
46  */
47 
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/device.h>
51 #include <sys/kernel.h>
52 #include <sys/rwlock.h>
53 #include <sys/proc.h>
54 #include <sys/timeout.h>
55 #ifdef __HAVE_TIMECOUNTER
56 #include <sys/timetc.h>
57 #endif
58 
59 #include <machine/bus.h>
60 
61 #include <dev/pci/pcivar.h>
62 #include <dev/pci/pcireg.h>
63 #include <dev/pci/pcidevs.h>
64 
65 #include <dev/rndvar.h>
66 #include <dev/i2c/i2cvar.h>
67 
68 #ifdef AMDPM_DEBUG
69 #define DPRINTF(x...) printf(x)
70 #else
71 #define DPRINTF(x...)
72 #endif
73 
74 #define AMDPM_SMBUS_DELAY	100
75 #define AMDPM_SMBUS_TIMEOUT	1
76 
77 #ifdef __HAVE_TIMECOUNTER
78 u_int amdpm_get_timecount(struct timecounter *tc);
79 
80 #ifndef AMDPM_FREQUENCY
81 #define AMDPM_FREQUENCY 3579545
82 #endif
83 
84 static struct timecounter amdpm_timecounter = {
85 	amdpm_get_timecount,	/* get_timecount */
86 	0,			/* no poll_pps */
87 	0xffffff,		/* counter_mask */
88 	AMDPM_FREQUENCY,	/* frequency */
89 	"AMDPM",		/* name */
90 	1000			/* quality */
91 };
92 #endif
93 
94 #define	AMDPM_CONFREG	0x40
95 
96 /* 0x40: General Configuration 1 Register */
97 #define	AMDPM_RNGEN	0x00000080	/* random number generator enable */
98 #define	AMDPM_STOPTMR	0x00000040	/* stop free-running timer */
99 
100 /* 0x41: General Configuration 2 Register */
101 #define	AMDPM_PMIOEN	0x00008000	/* system management IO space enable */
102 #define	AMDPM_TMRRST	0x00004000	/* reset free-running timer */
103 #define	AMDPM_TMR32	0x00000800	/* extended (32 bit) timer enable */
104 
105 /* 0x42: SCI Interrupt Configuration Register */
106 /* 0x43: Previous Power State Register */
107 
108 #define	AMDPM_PMPTR	0x58		/* PMxx System Management IO space
109 					   Pointer */
110 #define NFPM_PMPTR	0x14		/* nForce System Management IO space
111 					   POinter */
112 #define	AMDPM_PMBASE(x)	((x) & 0xff00)	/* PMxx base address */
113 #define	AMDPM_PMSIZE	256		/* PMxx space size */
114 
115 /* Registers in PMxx space */
116 #define	AMDPM_TMR	0x08		/* 24/32 bit timer register */
117 
118 #define	AMDPM_RNGDATA	0xf0		/* 32 bit random data register */
119 #define	AMDPM_RNGSTAT	0xf4		/* RNG status register */
120 #define	AMDPM_RNGDONE	0x00000001	/* Random number generation complete */
121 
122 #define AMDPM_SMB_REGS  0xe0		/* offset of SMB register space */
123 #define AMDPM_SMB_SIZE  0xf		/* size of SMB register space */
124 #define AMDPM_SMBSTAT	0x0		/* SMBus status */
125 #define AMDPM_SMBSTAT_ABRT	(1 << 0)	/* transfer abort */
126 #define AMDPM_SMBSTAT_COL	(1 << 1)	/* collision */
127 #define AMDPM_SMBSTAT_PRERR	(1 << 2)	/* protocol error */
128 #define AMDPM_SMBSTAT_HBSY	(1 << 3)	/* host controller busy */
129 #define AMDPM_SMBSTAT_CYC	(1 << 4)	/* cycle complete */
130 #define AMDPM_SMBSTAT_TO	(1 << 5)	/* timeout */
131 #define AMDPM_SMBSTAT_SNP	(1 << 8)	/* snoop address match */
132 #define AMDPM_SMBSTAT_SLV	(1 << 9)	/* slave address match */
133 #define AMDPM_SMBSTAT_SMBA	(1 << 10)	/* SMBALERT# asserted */
134 #define AMDPM_SMBSTAT_BSY	(1 << 11)	/* bus busy */
135 #define AMDPM_SMBSTAT_BITS	"\020\001ABRT\002COL\003PRERR\004HBSY\005CYC\006TO\011SNP\012SLV\013SMBA\014BSY"
136 #define AMDPM_SMBCTL	0x2		/* SMBus control */
137 #define AMDPM_SMBCTL_CMD_QUICK	0		/* QUICK command */
138 #define AMDPM_SMBCTL_CMD_BYTE	1		/* BYTE command */
139 #define AMDPM_SMBCTL_CMD_BDATA	2		/* BYTE DATA command */
140 #define AMDPM_SMBCTL_CMD_WDATA	3		/* WORD DATA command */
141 #define AMDPM_SMBCTL_CMD_PCALL	4		/* PROCESS CALL command */
142 #define AMDPM_SMBCTL_CMD_BLOCK	5		/* BLOCK command */
143 #define AMDPM_SMBCTL_START	(1 << 3)	/* start transfer */
144 #define AMDPM_SMBCTL_CYCEN	(1 << 4)	/* intr on cycle complete */
145 #define AMDPM_SMBCTL_ABORT	(1 << 5)	/* abort transfer */
146 #define AMDPM_SMBCTL_SNPEN	(1 << 8)	/* intr on snoop addr match */
147 #define AMDPM_SMBCTL_SLVEN	(1 << 9)	/* intr on slave addr match */
148 #define AMDPM_SMBCTL_SMBAEN	(1 << 10)	/* intr on SMBALERT# */
149 #define AMDPM_SMBADDR	0x4		/* SMBus address */
150 #define AMDPM_SMBADDR_READ	(1 << 0)	/* read direction */
151 #define AMDPM_SMBADDR_ADDR(x)	(((x) & 0x7f) << 1) /* 7-bit address */
152 #define AMDPM_SMBDATA	0x6		/* SMBus data */
153 #define AMDPM_SMBCMD	0x8		/* SMBus command */
154 
155 
156 struct amdpm_softc {
157 	struct device sc_dev;
158 
159 	pci_chipset_tag_t sc_pc;
160 	pcitag_t sc_tag;
161 
162 	bus_space_tag_t sc_iot;
163 	bus_space_handle_t sc_ioh;		/* PMxx space */
164 	bus_space_handle_t sc_i2c_ioh;		/* I2C space */
165 	int sc_poll;
166 
167 	struct timeout sc_rnd_ch;
168 
169 	struct i2c_controller sc_i2c_tag;
170 	struct rwlock sc_i2c_lock;
171 	struct {
172 		i2c_op_t op;
173 		void *buf;
174 		size_t len;
175 		int flags;
176 		volatile int error;
177 	} sc_i2c_xfer;
178 };
179 
180 int	amdpm_match(struct device *, void *, void *);
181 void	amdpm_attach(struct device *, struct device *, void *);
182 void	amdpm_rnd_callout(void *);
183 
184 int	amdpm_i2c_acquire_bus(void *, int);
185 void	amdpm_i2c_release_bus(void *, int);
186 int	amdpm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
187 	    void *, size_t, int);
188 
189 int	amdpm_intr(void *);
190 
191 struct cfattach amdpm_ca = {
192 	sizeof(struct amdpm_softc), amdpm_match, amdpm_attach
193 };
194 
195 struct cfdriver amdpm_cd = {
196 	NULL, "amdpm", DV_DULL
197 };
198 
199 const struct pci_matchid amdpm_ids[] = {
200 	{ PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC756_PMC },
201 	{ PCI_VENDOR_AMD, PCI_PRODUCT_AMD_766_PMC },
202 	{ PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC768_PMC },
203 	{ PCI_VENDOR_AMD, PCI_PRODUCT_AMD_8111_PMC },
204 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_SMB }
205 };
206 
207 int
208 amdpm_match(struct device *parent, void *match, void *aux)
209 {
210 	return (pci_matchbyid(aux, amdpm_ids,
211 	    sizeof(amdpm_ids) / sizeof(amdpm_ids[0])));
212 }
213 
214 void
215 amdpm_attach(struct device *parent, struct device *self, void *aux)
216 {
217 	struct amdpm_softc *sc = (struct amdpm_softc *) self;
218 	struct pci_attach_args *pa = aux;
219 	struct i2cbus_attach_args iba;
220 	pcireg_t cfg_reg, reg;
221 	int i;
222 
223 	sc->sc_pc = pa->pa_pc;
224 	sc->sc_tag = pa->pa_tag;
225 	sc->sc_iot = pa->pa_iot;
226 	sc->sc_poll = 1; /* XXX */
227 
228 
229 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD)  {
230 		cfg_reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMDPM_CONFREG);
231 		if ((cfg_reg & AMDPM_PMIOEN) == 0) {
232 			printf(": PMxx space isn't enabled\n");
233 			return;
234 		}
235 
236 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMDPM_PMPTR);
237 		if (AMDPM_PMBASE(reg) == 0 ||
238 		    bus_space_map(sc->sc_iot, AMDPM_PMBASE(reg), AMDPM_PMSIZE,
239 		    0, &sc->sc_ioh)) {
240 			printf("\n");
241 			return;
242 		}
243 		if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, AMDPM_SMB_REGS,
244 		    AMDPM_SMB_SIZE, &sc->sc_i2c_ioh)) {
245 			printf(": failed to map I2C subregion\n");
246 			return;
247 		}
248 
249 #ifdef __HAVE_TIMECOUNTER
250 		if ((cfg_reg & AMDPM_TMRRST) == 0 &&
251 		    (cfg_reg & AMDPM_STOPTMR) == 0 &&
252 		    (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_PBC768_PMC ||
253 		    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_8111_PMC)) {
254 			printf(": %d-bit timer at %dHz",
255 			    (cfg_reg & AMDPM_TMR32) ? 32 : 24,
256 			    amdpm_timecounter.tc_frequency);
257 
258 			amdpm_timecounter.tc_priv = sc;
259 			if (cfg_reg & AMDPM_TMR32)
260 				amdpm_timecounter.tc_counter_mask = 0xffffffffu;
261 			tc_init(&amdpm_timecounter);
262 		}
263 #endif
264 		if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_PBC768_PMC ||
265 		    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_8111_PMC) {
266 			if ((cfg_reg & AMDPM_RNGEN) ==0) {
267 				pci_conf_write(pa->pa_pc, pa->pa_tag,
268 				    AMDPM_CONFREG, cfg_reg | AMDPM_RNGEN);
269 				cfg_reg = pci_conf_read(pa->pa_pc, pa->pa_tag,
270 				    AMDPM_CONFREG);
271 			}
272 			if (cfg_reg & AMDPM_RNGEN) {
273 			/* Check to see if we can read data from the RNG. */
274 				(void) bus_space_read_4(sc->sc_iot, sc->sc_ioh,
275 				    AMDPM_RNGDATA);
276 				for (i = 1000; i--; ) {
277 					if (bus_space_read_1(sc->sc_iot,
278 					    sc->sc_ioh, AMDPM_RNGSTAT) &
279 					    AMDPM_RNGDONE)
280 						break;
281 					DELAY(10);
282 				}
283 				if (bus_space_read_1(sc->sc_iot, sc->sc_ioh,
284 				    AMDPM_RNGSTAT) & AMDPM_RNGDONE) {
285 					printf(": rng active");
286 					timeout_set(&sc->sc_rnd_ch,
287 					    amdpm_rnd_callout, sc);
288 					amdpm_rnd_callout(sc);
289 				}
290 			}
291 		}
292 	} else if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NVIDIA) {
293 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, NFPM_PMPTR);
294 		if (AMDPM_PMBASE(reg) == 0 ||
295 		    bus_space_map(sc->sc_iot, AMDPM_PMBASE(reg), AMDPM_SMB_SIZE, 0,
296 		    &sc->sc_i2c_ioh)) {
297 			printf(": failed to map I2C subregion\n");
298 			return;
299 		}
300 	}
301 	printf("\n");
302 
303 	/* Attach I2C bus */
304 	rw_init(&sc->sc_i2c_lock, "iiclk");
305 	sc->sc_i2c_tag.ic_cookie = sc;
306 	sc->sc_i2c_tag.ic_acquire_bus = amdpm_i2c_acquire_bus;
307 	sc->sc_i2c_tag.ic_release_bus = amdpm_i2c_release_bus;
308 	sc->sc_i2c_tag.ic_exec = amdpm_i2c_exec;
309 
310 	bzero(&iba, sizeof(iba));
311 	iba.iba_name = "iic";
312 	iba.iba_tag = &sc->sc_i2c_tag;
313 	config_found(self, &iba, iicbus_print);
314 }
315 
316 void
317 amdpm_rnd_callout(void *v)
318 {
319 	struct amdpm_softc *sc = v;
320 	u_int32_t reg;
321 
322 	if ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_RNGSTAT) &
323 	    AMDPM_RNGDONE) != 0) {
324 		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_RNGDATA);
325 		add_true_randomness(reg);
326 	}
327 	timeout_add(&sc->sc_rnd_ch, 1);
328 }
329 
330 #ifdef __HAVE_TIMECOUNTER
331 u_int
332 amdpm_get_timecount(struct timecounter *tc)
333 {
334 	struct amdpm_softc *sc = tc->tc_priv;
335 	u_int u2;
336 #if 0
337 	u_int u1, u3;
338 #endif
339 
340 	u2 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
341 #if 0
342 	u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
343 	do {
344 		u1 = u2;
345 		u2 = u3;
346 		u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
347 	} while (u1 > u2 || u2 > u3);
348 #endif
349 	return (u2);
350 }
351 #endif
352 
353 int
354 amdpm_i2c_acquire_bus(void *cookie, int flags)
355 {
356 	struct amdpm_softc *sc = cookie;
357 
358 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
359 		return (0);
360 
361 	return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
362 }
363 
364 void
365 amdpm_i2c_release_bus(void *cookie, int flags)
366 {
367 	struct amdpm_softc *sc = cookie;
368 
369 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
370 		return;
371 
372 	rw_exit(&sc->sc_i2c_lock);
373 }
374 
375 int
376 amdpm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
377     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
378 {
379 	struct amdpm_softc *sc = cookie;
380 	u_int8_t *b;
381 	u_int16_t st, ctl, data;
382 	int retries;
383 
384 	DPRINTF("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
385 	    "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen,
386 	    len, flags);
387 
388 	/* Wait for bus to be idle */
389 	for (retries = 100; retries > 0; retries--) {
390 		st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
391 		if (!(st & AMDPM_SMBSTAT_BSY))
392 			break;
393 		DELAY(AMDPM_SMBUS_DELAY);
394 	}
395 	DPRINTF("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,
396 	    AMDPM_SMBSTAT_BITS);
397 	if (st & AMDPM_SMBSTAT_BSY)
398 		return (1);
399 
400 	if (cold || sc->sc_poll)
401 		flags |= I2C_F_POLL;
402 
403 	if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
404 		return (1);
405 
406 	/* Setup transfer */
407 	sc->sc_i2c_xfer.op = op;
408 	sc->sc_i2c_xfer.buf = buf;
409 	sc->sc_i2c_xfer.len = len;
410 	sc->sc_i2c_xfer.flags = flags;
411 	sc->sc_i2c_xfer.error = 0;
412 
413 	/* Set slave address and transfer direction */
414 	bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBADDR,
415 	    AMDPM_SMBADDR_ADDR(addr) |
416 	    (I2C_OP_READ_P(op) ? AMDPM_SMBADDR_READ : 0));
417 
418 	b = (void *)cmdbuf;
419 	if (cmdlen > 0)
420 		/* Set command byte */
421 		bus_space_write_1(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCMD, b[0]);
422 
423 	if (I2C_OP_WRITE_P(op)) {
424 		/* Write data */
425 		data = 0;
426 		b = buf;
427 		if (len > 0)
428 			data = b[0];
429 		if (len > 1)
430 			data |= ((u_int16_t)b[1] << 8);
431 		if (len > 0)
432 			bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh,
433 			    AMDPM_SMBDATA, data);
434 	}
435 
436 	/* Set SMBus command */
437 	if (len == 0)
438 		ctl = AMDPM_SMBCTL_CMD_BYTE;
439 	else if (len == 1)
440 		ctl = AMDPM_SMBCTL_CMD_BDATA;
441 	else if (len == 2)
442 		ctl = AMDPM_SMBCTL_CMD_WDATA;
443 
444 	if ((flags & I2C_F_POLL) == 0)
445 		ctl |= AMDPM_SMBCTL_CYCEN;
446 
447 	/* Start transaction */
448 	ctl |= AMDPM_SMBCTL_START;
449 	bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCTL, ctl);
450 
451 	if (flags & I2C_F_POLL) {
452 		/* Poll for completion */
453 		DELAY(AMDPM_SMBUS_DELAY);
454 		for (retries = 1000; retries > 0; retries--) {
455 			st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh,
456 			    AMDPM_SMBSTAT);
457 			if ((st & AMDPM_SMBSTAT_HBSY) == 0)
458 				break;
459 			DELAY(AMDPM_SMBUS_DELAY);
460 		}
461 		if (st & AMDPM_SMBSTAT_HBSY)
462 			goto timeout;
463 		amdpm_intr(sc);
464 	} else {
465 		/* Wait for interrupt */
466 		if (tsleep(sc, PRIBIO, "iicexec", AMDPM_SMBUS_TIMEOUT * hz))
467 			goto timeout;
468 	}
469 
470 	if (sc->sc_i2c_xfer.error)
471 		return (1);
472 
473 	return (0);
474 
475 timeout:
476 	/*
477 	 * Transfer timeout. Kill the transaction and clear status bits.
478 	 */
479 	printf("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
480 	    "flags 0x%02x: timeout, status 0x%b\n",
481 	    sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags,
482 	    st, AMDPM_SMBSTAT_BITS);
483 	bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCTL,
484 	    AMDPM_SMBCTL_ABORT);
485 	DELAY(AMDPM_SMBUS_DELAY);
486 	st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
487 	if ((st & AMDPM_SMBSTAT_ABRT) == 0)
488 		printf("%s: abort failed, status 0x%b\n",
489 		    sc->sc_dev.dv_xname, st, AMDPM_SMBSTAT_BITS);
490 	bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT, st);
491 	return (1);
492 }
493 
494 int
495 amdpm_intr(void *arg)
496 {
497 	struct amdpm_softc *sc = arg;
498 	u_int16_t st, data;
499 	u_int8_t *b;
500 	size_t len;
501 
502 	/* Read status */
503 	st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
504 	if ((st & AMDPM_SMBSTAT_HBSY) != 0 || (st & (AMDPM_SMBSTAT_ABRT |
505 	    AMDPM_SMBSTAT_COL | AMDPM_SMBSTAT_PRERR | AMDPM_SMBSTAT_CYC |
506 	    AMDPM_SMBSTAT_TO | AMDPM_SMBSTAT_SNP | AMDPM_SMBSTAT_SLV |
507 	    AMDPM_SMBSTAT_SMBA)) == 0)
508 		/* Interrupt was not for us */
509 		return (0);
510 
511 	DPRINTF("%s: intr: st 0x%b\n", sc->sc_dev.dv_xname, st,
512 	    AMDPM_SMBSTAT_BITS);
513 
514 	/* Clear status bits */
515 	bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT, st);
516 
517 	/* Check for errors */
518 	if (st & (AMDPM_SMBSTAT_COL | AMDPM_SMBSTAT_PRERR |
519 	    AMDPM_SMBSTAT_TO)) {
520 		sc->sc_i2c_xfer.error = 1;
521 		goto done;
522 	}
523 
524 	if (st & AMDPM_SMBSTAT_CYC) {
525 		if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
526 			goto done;
527 
528 		/* Read data */
529 		b = sc->sc_i2c_xfer.buf;
530 		len = sc->sc_i2c_xfer.len;
531 		if (len > 0) {
532 			data = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh,
533 			    AMDPM_SMBDATA);
534 			b[0] = data & 0xff;
535 		}
536 		if (len > 1)
537 			b[1] = (data >> 8) & 0xff;
538 	}
539 
540 done:
541 	if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
542 		wakeup(sc);
543 	return (1);
544 }
545