amdpm.c revision 1.16
1/*	$OpenBSD: amdpm.c,v 1.16 2006/03/08 22:59:14 dlg 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 * 3. All advertising materials mentioning features or use of this software
35 *    must display the following acknowledgement:
36 *	This product includes software developed by the NetBSD
37 *	Foundation, Inc. and its contributors.
38 * 4. Neither the name of The NetBSD Foundation nor the names of its
39 *    contributors may be used to endorse or promote products derived
40 *    from this software without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
43 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
44 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
45 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
46 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
47 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
48 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
49 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
50 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
52 * POSSIBILITY OF SUCH DAMAGE.
53 */
54
55#include <sys/param.h>
56#include <sys/systm.h>
57#include <sys/device.h>
58#include <sys/kernel.h>
59#include <sys/lock.h>
60#include <sys/proc.h>
61#include <sys/timeout.h>
62#ifdef __HAVE_TIMECOUNTER
63#include <sys/timetc.h>
64#endif
65
66#include <machine/bus.h>
67
68#include <dev/pci/pcivar.h>
69#include <dev/pci/pcireg.h>
70#include <dev/pci/pcidevs.h>
71
72#include <dev/pci/amdpmreg.h>
73
74#include <dev/rndvar.h>
75#include <dev/i2c/i2cvar.h>
76
77#ifdef AMDPM_DEBUG
78#define DPRINTF(x...) printf(x)
79#else
80#define DPRINTF(x...)
81#endif
82
83#define AMDPM_SMBUS_DELAY	100
84#define AMDPM_SMBUS_TIMEOUT	1
85
86#ifdef __HAVE_TIMECOUNTER
87u_int amdpm_get_timecount(struct timecounter *tc);
88
89#ifndef AMDPM_FREQUENCY
90#define AMDPM_FREQUENCY 3579545
91#endif
92
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
155static struct timecounter amdpm_timecounter = {
156	amdpm_get_timecount,	/* get_timecount */
157	0,			/* no poll_pps */
158	0xffffff,		/* counter_mask */
159	AMDPM_FREQUENCY,	/* frequency */
160	"AMDPM",		/* name */
161	1000			/* quality */
162};
163#endif
164
165struct amdpm_softc {
166	struct device sc_dev;
167
168	pci_chipset_tag_t sc_pc;
169	pcitag_t sc_tag;
170
171	bus_space_tag_t sc_iot;
172	bus_space_handle_t sc_ioh;		/* PMxx space */
173	bus_space_handle_t sc_i2c_ioh;		/* I2C space */
174	int sc_poll;
175
176	struct timeout sc_rnd_ch;
177
178	struct i2c_controller sc_i2c_tag;
179	struct lock sc_i2c_lock;
180	struct {
181		i2c_op_t op;
182		void *buf;
183		size_t len;
184		int flags;
185		volatile int error;
186	} sc_i2c_xfer;
187};
188
189int	amdpm_match(struct device *, void *, void *);
190void	amdpm_attach(struct device *, struct device *, void *);
191void	amdpm_rnd_callout(void *);
192
193int	amdpm_i2c_acquire_bus(void *, int);
194void	amdpm_i2c_release_bus(void *, int);
195int	amdpm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
196	    void *, size_t, int);
197
198int	amdpm_intr(void *);
199
200struct cfattach amdpm_ca = {
201	sizeof(struct amdpm_softc), amdpm_match, amdpm_attach
202};
203
204struct cfdriver amdpm_cd = {
205	NULL, "amdpm", DV_DULL
206};
207
208const struct pci_matchid amdpm_ids[] = {
209	{ PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC756_PMC },
210	{ PCI_VENDOR_AMD, PCI_PRODUCT_AMD_766_PMC },
211	{ PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC768_PMC },
212	{ PCI_VENDOR_AMD, PCI_PRODUCT_AMD_8111_PMC },
213	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_SMB }
214};
215
216int
217amdpm_match(struct device *parent, void *match, void *aux)
218{
219	return (pci_matchbyid(aux, amdpm_ids,
220	    sizeof(amdpm_ids) / sizeof(amdpm_ids[0])));
221}
222
223void
224amdpm_attach(struct device *parent, struct device *self, void *aux)
225{
226	struct amdpm_softc *sc = (struct amdpm_softc *) self;
227	struct pci_attach_args *pa = aux;
228	struct i2cbus_attach_args iba;
229	pcireg_t cfg_reg, reg;
230	int i;
231
232	sc->sc_pc = pa->pa_pc;
233	sc->sc_tag = pa->pa_tag;
234	sc->sc_iot = pa->pa_iot;
235	sc->sc_poll = 1; /* XXX */
236
237
238	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD)  {
239		cfg_reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMDPM_CONFREG);
240		if ((cfg_reg & AMDPM_PMIOEN) == 0) {
241			printf(": PMxx space isn't enabled\n");
242			return;
243		}
244
245		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMDPM_PMPTR);
246		if (bus_space_map(sc->sc_iot, AMDPM_PMBASE(reg), AMDPM_PMSIZE, 0,
247		    &sc->sc_ioh)) {
248			printf(": failed to map PMxx space\n");
249			return;
250		}
251		if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, AMDPM_SMB_REGS,
252		    AMDPM_SMB_SIZE, &sc->sc_i2c_ioh)) {
253			printf(": failed to map I2C subregion\n");
254			return;
255		}
256
257#ifdef __HAVE_TIMECOUNTER
258		if ((cfg_reg & AMDPM_TMRRST) == 0 &&
259		    (cfg_reg & AMDPM_STOPTMR) == 0 &&
260		    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_PBC768_PMC) {
261			printf(": %d-bit timer at %dHz",
262			    (cfg_reg & AMDPM_TMR32) ? 32 : 24,
263			    amdpm_timecounter.tc_frequency);
264
265			amdpm_timecounter.tc_priv = sc;
266			if (cfg_reg & AMDPM_TMR32)
267				amdpm_timecounter.tc_counter_mask = 0xffffffffu;
268			tc_init(&amdpm_timecounter);
269		}
270#endif
271		if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_PBC768_PMC ||
272		    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_8111_PMC) {
273			if ((cfg_reg & AMDPM_RNGEN) ==0) {
274				pci_conf_write(pa->pa_pc, pa->pa_tag,
275				    AMDPM_CONFREG, cfg_reg | AMDPM_RNGEN);
276				cfg_reg = pci_conf_read(pa->pa_pc, pa->pa_tag,
277				    AMDPM_CONFREG);
278			}
279			if (cfg_reg & AMDPM_RNGEN) {
280			/* Check to see if we can read data from the RNG. */
281				(void) bus_space_read_4(sc->sc_iot, sc->sc_ioh,
282				    AMDPM_RNGDATA);
283				for (i = 1000; i--; ) {
284					if (bus_space_read_1(sc->sc_iot,
285					    sc->sc_ioh, AMDPM_RNGSTAT) &
286					    AMDPM_RNGDONE)
287						break;
288					DELAY(10);
289				}
290				if (bus_space_read_1(sc->sc_iot, sc->sc_ioh,
291				    AMDPM_RNGSTAT) & AMDPM_RNGDONE) {
292					printf(": rng active");
293					timeout_set(&sc->sc_rnd_ch,
294					    amdpm_rnd_callout, sc);
295					amdpm_rnd_callout(sc);
296				}
297			}
298		}
299	} else if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NVIDIA) {
300		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, NFPM_PMPTR);
301		if (bus_space_map(sc->sc_iot, AMDPM_PMBASE(reg), AMDPM_SMB_SIZE, 0,
302		    &sc->sc_i2c_ioh)) {
303			printf(": failed to map I2C subregion\n");
304			return;
305		}
306	}
307	printf("\n");
308
309	/* Attach I2C bus */
310	lockinit(&sc->sc_i2c_lock, PRIBIO | PCATCH, "iiclk", 0, 0);
311	sc->sc_i2c_tag.ic_cookie = sc;
312	sc->sc_i2c_tag.ic_acquire_bus = amdpm_i2c_acquire_bus;
313	sc->sc_i2c_tag.ic_release_bus = amdpm_i2c_release_bus;
314	sc->sc_i2c_tag.ic_exec = amdpm_i2c_exec;
315
316	bzero(&iba, sizeof(iba));
317	iba.iba_name = "iic";
318	iba.iba_tag = &sc->sc_i2c_tag;
319	config_found(self, &iba, iicbus_print);
320}
321
322void
323amdpm_rnd_callout(void *v)
324{
325	struct amdpm_softc *sc = v;
326	u_int32_t reg;
327
328	if ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_RNGSTAT) &
329	    AMDPM_RNGDONE) != 0) {
330		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_RNGDATA);
331		add_true_randomness(reg);
332	}
333	timeout_add(&sc->sc_rnd_ch, 1);
334}
335
336#ifdef __HAVE_TIMECOUNTER
337u_int
338amdpm_get_timecount(struct timecounter *tc)
339{
340	struct amdpm_softc *sc = tc->tc_priv;
341	u_int u2;
342#if 0
343	u_int u1, u3;
344#endif
345
346	u2 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
347#if 0
348	u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
349	do {
350		u1 = u2;
351		u2 = u3;
352		u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
353	} while (u1 > u2 || u2 > u3);
354#endif
355	return (u2);
356}
357#endif
358
359int
360amdpm_i2c_acquire_bus(void *cookie, int flags)
361{
362	struct amdpm_softc *sc = cookie;
363
364	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
365		return (0);
366
367	return (lockmgr(&sc->sc_i2c_lock, LK_EXCLUSIVE, NULL));
368}
369
370void
371amdpm_i2c_release_bus(void *cookie, int flags)
372{
373	struct amdpm_softc *sc = cookie;
374
375	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
376		return;
377
378	lockmgr(&sc->sc_i2c_lock, LK_RELEASE, NULL);
379}
380
381int
382amdpm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
383    const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
384{
385	struct amdpm_softc *sc = cookie;
386	u_int8_t *b;
387	u_int16_t st, ctl, data;
388	int retries;
389
390	DPRINTF("%s: exec: op %d, addr 0x%x, cmdlen %d, len %d, flags 0x%x\n",
391	    sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags);
392
393	/* Wait for bus to be idle */
394	for (retries = 100; retries > 0; retries--) {
395		st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
396		if (!(st & AMDPM_SMBSTAT_BSY))
397			break;
398		DELAY(AMDPM_SMBUS_DELAY);
399	}
400	DPRINTF("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,
401	    AMDPM_SMBSTAT_BITS);
402	if (st & AMDPM_SMBSTAT_BSY)
403		return (1);
404
405	if (cold || sc->sc_poll)
406		flags |= I2C_F_POLL;
407
408	if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
409		return (1);
410
411	/* Setup transfer */
412	sc->sc_i2c_xfer.op = op;
413	sc->sc_i2c_xfer.buf = buf;
414	sc->sc_i2c_xfer.len = len;
415	sc->sc_i2c_xfer.flags = flags;
416	sc->sc_i2c_xfer.error = 0;
417
418	/* Set slave address and transfer direction */
419	bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBADDR,
420	    AMDPM_SMBADDR_ADDR(addr) |
421	    (I2C_OP_READ_P(op) ? AMDPM_SMBADDR_READ : 0));
422
423	b = (void *)cmdbuf;
424	if (cmdlen > 0)
425		/* Set command byte */
426		bus_space_write_1(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCMD, b[0]);
427
428	if (I2C_OP_WRITE_P(op)) {
429		/* Write data */
430		data = 0;
431		b = buf;
432		if (len > 0)
433			data = b[0];
434		if (len > 1)
435			data |= ((u_int16_t)b[1] << 8);
436		if (len > 0)
437			bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh,
438			    AMDPM_SMBDATA, data);
439	}
440
441	/* Set SMBus command */
442	if (len == 0)
443		ctl = AMDPM_SMBCTL_CMD_BYTE;
444	else if (len == 1)
445		ctl = AMDPM_SMBCTL_CMD_BDATA;
446	else if (len == 2)
447		ctl = AMDPM_SMBCTL_CMD_WDATA;
448
449	if ((flags & I2C_F_POLL) == 0)
450		ctl |= AMDPM_SMBCTL_CYCEN;
451
452	/* Start transaction */
453	ctl |= AMDPM_SMBCTL_START;
454	bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCTL, ctl);
455
456	if (flags & I2C_F_POLL) {
457		/* Poll for completion */
458		DELAY(AMDPM_SMBUS_DELAY);
459		for (retries = 1000; retries > 0; retries--) {
460			st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh,
461			    AMDPM_SMBSTAT);
462			if ((st & AMDPM_SMBSTAT_HBSY) == 0)
463				break;
464			DELAY(AMDPM_SMBUS_DELAY);
465		}
466		if (st & AMDPM_SMBSTAT_HBSY)
467			goto timeout;
468		amdpm_intr(sc);
469	} else {
470		/* Wait for interrupt */
471		if (tsleep(sc, PRIBIO, "iicexec", AMDPM_SMBUS_TIMEOUT * hz))
472			goto timeout;
473	}
474
475	if (sc->sc_i2c_xfer.error)
476		return (1);
477
478	return (0);
479
480timeout:
481	/*
482	 * Transfer timeout. Kill the transaction and clear status bits.
483	 */
484	printf("%s: timeout, status 0x%b\n", sc->sc_dev.dv_xname, st,
485	    AMDPM_SMBSTAT_BITS);
486	bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCTL,
487	    AMDPM_SMBCTL_ABORT);
488	DELAY(AMDPM_SMBUS_DELAY);
489	st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
490	if ((st & AMDPM_SMBSTAT_ABRT) == 0)
491		printf("%s: transaction abort failed, status 0x%b\n",
492		    sc->sc_dev.dv_xname, st, AMDPM_SMBSTAT_BITS);
493	bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT, st);
494	return (1);
495}
496
497int
498amdpm_intr(void *arg)
499{
500	struct amdpm_softc *sc = arg;
501	u_int16_t st, data;
502	u_int8_t *b;
503	size_t len;
504
505	/* Read status */
506	st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
507	if ((st & AMDPM_SMBSTAT_HBSY) != 0 || (st & (AMDPM_SMBSTAT_ABRT |
508	    AMDPM_SMBSTAT_COL | AMDPM_SMBSTAT_PRERR | AMDPM_SMBSTAT_CYC |
509	    AMDPM_SMBSTAT_TO | AMDPM_SMBSTAT_SNP | AMDPM_SMBSTAT_SLV |
510	    AMDPM_SMBSTAT_SMBA)) == 0)
511		/* Interrupt was not for us */
512		return (0);
513
514	DPRINTF("%s: intr: st 0x%b\n", sc->sc_dev.dv_xname, st,
515	    AMDPM_SMBSTAT_BITS);
516
517	/* Clear status bits */
518	bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT, st);
519
520	/* Check for errors */
521	if (st & (AMDPM_SMBSTAT_COL | AMDPM_SMBSTAT_PRERR |
522	    AMDPM_SMBSTAT_TO)) {
523		sc->sc_i2c_xfer.error = 1;
524		goto done;
525	}
526
527	if (st & AMDPM_SMBSTAT_CYC) {
528		if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
529			goto done;
530
531		/* Read data */
532		b = sc->sc_i2c_xfer.buf;
533		len = sc->sc_i2c_xfer.len;
534		if (len > 0) {
535			data = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh,
536			    AMDPM_SMBDATA);
537			b[0] = data & 0xff;
538		}
539		if (len > 1)
540			b[1] = (data >> 8) & 0xff;
541	}
542
543done:
544	if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
545		wakeup(sc);
546	return (1);
547}
548