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