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