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