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